什么是 CSRF(跨站请求伪造)?如何防御?
CSRF(Cross-Site Request Forgery,跨站请求伪造) 是一种网络安全攻击方式。
简单来说,攻击者诱导受害者访问一个恶意网站,利用受害者在已登录的目标网站(如银行、社交媒体)上的身份,在受害者不知情的情况下,以受害者的名义发送恶意请求(如转账、发帖、改密)。
一、 通俗易懂的攻击原理(举例)
假设你正在使用网银,并且已经登录了 A银行 的网站(你的浏览器里存有 A银行的 Cookie)。
正常场景:你想给朋友转账 100 元,你点击按钮,浏览器发送请求:
GET http://bank-a.com/transfer?to=Friend&amount=100
银行收到请求,检查你的 Cookie,确认是你本人,转账成功。CSRF 攻击场景:
- 你登录了 A银行,没有退出(Cookie 还有效)。
- 你手滑点开了一个恶意网站 B(或者是一封钓鱼邮件)。
- 恶意网站 B 的页面里隐藏了一段代码(例如一张不可见的图片):
<img src="http://bank-a.com/transfer?to=Hacker&amount=10000"> - 当你的浏览器加载这张“图片”时,会自动向
bank-a.com发送请求。 - 关键点:浏览器会自动带上你之前在 A银行 的 Cookie。
- 后果:A银行的服务器收到请求,看到 Cookie 是合法的,以为是你本人操作的,于是你的 10000 元就被转给了黑客。
核心问题在于: 服务器无法区分这个请求是你“自愿点击”发出的,还是浏览器“被动加载”发出的,因为它只认 Cookie。
二、 如何防御 CSRF?
防御 CSRF 的核心思路是:在请求中添加一个攻击者无法伪造的信息,或者阻止浏览器自动发送 Cookie。
以下是几种主流的防御策略:
1. 使用 CSRF Token(最推荐,标准做法)
这是目前最安全的防御方式。
- 原理:
- 用户登录后,服务器生成一个随机的、不可预测的字符串(Token),并将其存储在用户的 Session 中。
- 每次页面加载时,服务器将这个 Token 放入 HTML 表单的隐藏字段中(或者放在 Meta 标签里)。
- 当用户提交表单(如转账)时,必须将这个 Token 一并提交。
- 服务器验证:提交上来的 Token 是否与 Session 中的 Token 一致。
- 为什么有效?
- 攻击者的恶意网站虽然能利用 Cookie 发送请求,但受限于浏览器的同源策略,攻击者无法读取 A银行页面的内容,因此无法获取这个随机的 Token。
- 没有 Token,请求就会被服务器拒绝。
2. 设置 Cookie 的 SameSite 属性(浏览器层面的防御)
这是一种较新的、成本极低的防御方式。通过设置 Cookie 的属性,告诉浏览器在跨站请求时不要发送 Cookie。
- 属性值:
SameSite=Strict:严格模式。任何跨站请求(比如从 B网站 点链接跳到 A网站)都不会携带 Cookie。安全性最高,但用户体验较差(每次跳转都要重新登录)。SameSite=Lax:宽松模式(现代浏览器默认值)。只有在顶层导航(如点击链接跳转)且是 GET 请求时才发送 Cookie;像图片加载、表单 POST 提交等跨站请求不发送 Cookie。这能防御绝大多数 CSRF 攻击。SameSite=None:无论是否跨站都发送 Cookie(必须配合Secure属性使用)。
3. 验证 Referer 和 Origin 字段
HTTP 协议头中包含 Referer 和 Origin 字段,它们记录了请求的来源地址。
- 原理:服务器检查请求头,如果发现请求来源(Origin)不是自家的域名(比如来自
evil.com),直接拒绝。 - 缺点:
- Referer 可以被伪造(虽然难,但在某些老旧浏览器或特定环境下可能)。
- 出于隐私保护,有些用户或浏览器插件会禁止发送 Referer,导致正常用户无法使用。
- 建议:仅作为辅助防御手段,不要作为唯一手段。
4. 二次验证(针对关键操作)
在进行敏感操作(如转账、修改密码、删除账号)时,强制要求用户进行交互。
- 手段:输入图形验证码、手机短信验证码、或者重新输入登录密码。
- 原理:攻击者无法预知验证码,也无法代替用户进行输入。
三、 总结
- CSRF 是什么:利用用户的登录态(Cookie),冒充用户在受信任网站上执行非本意的操作。
- 怎么防:
- 首选:后端实现 CSRF Token 校验。
- 辅助:配置 Cookie 的 SameSite 属性为
Lax或Strict。 - 关键操作:增加验证码或二次密码确认。