什么是 CSRF 攻击 (跨站请求伪造)?如何防御?
CSRF(Cross-Site Request Forgery,跨站请求伪造),也被称为 "One Click Attack" 或 "Session Riding",是一种网络安全攻击方式。
简单来说,攻击者盗用了你的身份,以你的名义发送恶意请求。
1. CSRF 攻击的原理
要理解 CSRF,首先要明白浏览器的一个机制:当你向某个网站发送请求时,浏览器会自动带上该网站的 Cookies。
攻击流程举例(经典的银行转账例子):
假设你正在使用网银,并且已经登录了。
- 受害者登录: 你登录了
bank.com,服务器给你发了一个 Cookie 用于维持登录状态。 - 受害者访问恶意网站: 你没有登出网银,在同一个浏览器的新标签页里访问了一个恶意网站
evil.com(可能是点击了钓鱼邮件里的链接)。 - 恶意代码执行:
evil.com的页面里隐藏了一段代码(例如一个不可见的图片或自动提交的表单):html<!-- 这是一个 GET 请求类型的 CSRF --> <img src="http://bank.com/transfer?to=hacker&money=1000" style="display:none;"> - 浏览器发送请求: 浏览器加载该图片时,会向
bank.com发起请求。关键点在于:浏览器发现你是向bank.com发请求,于是自动把你之前的登录 Cookie 带上了。 - 服务器执行:
bank.com的服务器收到请求,检查 Cookie 发现是合法的登录用户(你),于是执行了转账操作。
结果: 你的钱被转走了,但你毫不知情,银行服务器也以为是你自己操作的。
2. CSRF 的特点
- 攻击者无法获取你的 Cookie 内容: 攻击者只是让浏览器“借用”你的 Cookie 发送请求,但他自己看不到 Cookie 的具体字符(受同源策略限制)。
- 攻击者只能“借刀杀人”: 他能利用你的身份发请求(改密码、发帖、转账),但不能查看你的响应数据(比如他不能通过 CSRF 看到你的余额,因为响应数据回到了你的浏览器,而不是他的服务器)。
3. 如何防御 CSRF 攻击?
防御的核心思想是:服务器需要一种机制来区分“用户点击的合法请求”和“浏览器自动发起的伪造请求”。
以下是几种主流的防御策略:
1. 使用 CSRF Token (最推荐,标准做法)
这是目前最安全的防御方法。
- 原理:
- 用户访问表单页面时,服务器生成一个随机的、不可预测的字符串(Token),并将其放入 HTML 表单的隐藏字段中(或者放在 HTTP Header 中)。
- 用户提交表单时,这个 Token 会随数据一起发送给服务器。
- 服务器比对提交上来的 Token 和服务器存储的 Token 是否一致。
- 为什么有效?
攻击者虽然可以伪造请求,但他无法读取目标网站的页面内容(受同源策略限制),因此他拿不到这个随机的 Token。没有 Token,服务器就会拒绝请求。
2. 设置 Cookie 的 SameSite 属性
这是一种通过浏览器层面防御的简单有效方法。
- 原理: 在服务器设置 Cookie 时,增加
SameSite属性。SameSite=Strict:浏览器完全禁止第三方 Cookie。只有当前网页 URL 与请求目标一致时才发送 Cookie。SameSite=Lax(现代浏览器默认值):在跨站的 POST 请求(如表单提交、AJAX)中不发送 Cookie,但在跨站的 GET 请求(如点击链接跳转)中会发送。这能防御大部分 CSRF。
- 优点: 配置简单,无需修改代码逻辑。
- 缺点: 依赖浏览器版本(旧浏览器不支持),且
Strict模式可能会影响用户体验(如从百度跳转到你的网站时需要重新登录)。
3. 验证 Referer 和 Origin 字段
- 原理: HTTP 协议头中包含
Referer(来源页面) 和Origin(来源域名)。服务器可以检查这些字段,如果发现请求来源于evil.com而不是自家的域名,就拒绝请求。 - 缺点:
- Referer 可以被伪造(虽然较难)。
- 出于隐私保护,有些用户或浏览器插件会禁止发送 Referer,导致正常用户无法使用。
- 通常作为辅助防御手段,不建议单独使用。
4. 双重 Cookie 验证 (Double Submit Cookie)
- 原理:
- 用户访问页面时,服务器生成一个随机值,放在 Cookie 中。
- 前端脚本在发送请求时,从 Cookie 中读取这个值,并将其放入请求参数(或 Header)中。
- 服务器验证:Cookie 中的值 == 请求参数中的值。
- 为什么有效? 攻击者可以诱导浏览器发送 Cookie,但他无法通过脚本读取 Cookie 的值(如果没开启 HttpOnly)并将其填入参数中。
- 适用场景: 前后端分离,且无法使用服务端 Session 存储 Token 时。
5. 关键操作增加用户互动 (验证码/二次验证)
- 在转账、修改密码等关键操作前,强制要求用户输入验证码或再次输入密码。
- 原理: 攻击者无法预知验证码,也无法代替用户进行交互。这是最彻底的防御,但会牺牲用户体验。
总结
- CSRF 是什么: 攻击者利用用户的登录状态,诱导浏览器向受信任网站发送恶意请求。
- 核心防御:
- CSRF Token (首选,服务端生成随机令牌)。
- SameSite Cookie (配置 Cookie 属性,禁止跨站发送)。
- 关键操作加验证码。