跨站请求伪造(CSRF)的底层原理、攻击场景与防御策略详解
1. 描述
跨站请求伪造(CSRF)是一种恶意攻击手段,攻击者诱使已登录用户在不知情的情况下,向当前已登录的 Web 应用发送一个恶意请求,从而执行未经授权的操作(例如转账、修改密码、发表评论等)。攻击的核心在于滥用浏览器在用户访问网站时自动附带认证凭证(如 Cookie、Session)的机制。它与 XSS 不同,XSS 是利用用户对网站的信任,而 CSRF 是利用网站对用户浏览器的信任。
2. 知识背景铺垫
要理解 CSRF,需明确以下机制:
- 浏览器同源策略:限制来自 A 源的脚本访问 B 源的数据,但对发送请求的限制较松。例如,通过
<img>、<form>等标签向任意源发起 GET/POST 请求是被允许的。 - Cookie 自动携带:浏览器在向某域名发送请求时,会自动附带上该域名下的 Cookie(包括 Session Cookie),无论请求来源是用户主动点击还是页面中的隐藏请求。
- 认证机制依赖:许多 Web 应用仅依赖 Cookie/Session 来验证用户身份,如果请求携带有效 Session Cookie,服务器就认为是合法用户的操作。
3. 攻击原理详解
攻击分为三个步骤:
- 用户登录目标网站:用户通过认证,在浏览器中保存了网站的 Session Cookie。
- 用户访问恶意网站:攻击者诱使用户访问包含恶意代码的第三方网站(如通过邮件链接、论坛图片等)。
- 自动发起伪造请求:恶意网站中隐藏了一个自动向目标网站发起请求的代码,浏览器会自动携带目标网站的 Cookie,请求在用户不知情下被执行。
4. 攻击场景与代码示例
假设目标网站 bank.com 有一个转账接口:
POST /transfer HTTP/1.1
Host: bank.com
Content-Type: application/x-www-form-urlencoded
to_account=attacker&amount=1000
攻击者构造一个恶意页面,用户访问时会自动提交表单:
<!-- 恶意网站页面 -->
<form id="csrf-form" action="https://bank.com/transfer" method="POST">
<input type="hidden" name="to_account" value="attacker">
<input type="hidden" name="amount" value="1000">
</form>
<script>
document.getElementById('csrf-form').submit();
</script>
若用户已登录 bank.com,浏览器会自动带上该站点的 Cookie,服务器认为这是合法请求,完成转账。
5. 关键攻击条件
- 目标网站使用 Cookie/Session 认证。
- 目标网站接口没有足够的 CSRF 防护。
- 用户已登录目标网站,且浏览器保存了有效 Cookie。
- 用户访问了攻击者控制的页面。
6. 防御策略层层递进
6.1 验证请求来源(Referer/Origin 检查)
服务器检查 HTTP 头中的 Referer 或 Origin 字段,确保请求来自同源域名。
- 优点:简单易实现。
- 缺点:某些浏览器可能不发送这些头,或用户可以禁用;如果网站允许来自其他可信域名的请求,则需要维护白名单。
6.2 使用 CSRF Token
这是最主流的防御方案,步骤如下:
- 用户访问页面时,服务器生成一个随机、不可预测的 Token(如加密的随机字符串),存储在服务端 Session 或加密的 Cookie 中,并同时嵌入到页面的表单(或 Meta 标签)中。
- 当用户提交表单时,必须将该 Token 通过请求体(POST 参数)或请求头(X-CSRF-Token)发送到服务器。
- 服务器验证请求中的 Token 是否与 Session/Cookie 中存储的一致,不一致则拒绝请求。
为什么能防御:恶意网站无法获取 Token 值(受同源策略保护),因此无法构造包含有效 Token 的请求。
6.3 双重 Cookie 验证
将 Token 放在 Cookie 中,同时要求请求时从 Cookie 中读取 Token 并作为请求参数或请求头再次发送。服务器比较两者是否一致。
- 优点:无需在服务端存储 Token,实现简单。
- 缺点:如果网站存在 XSS 漏洞,可能被攻击者读取 Cookie 中的 Token;需注意 Cookie 作用域设置。
6.4 SameSite Cookie 属性
设置 Cookie 的 SameSite 属性,限制 Cookie 在跨站请求时不被发送。
SameSite=Strict:完全禁止跨站携带 Cookie。SameSite=Lax:允许部分安全跨站请求(如顶级导航)携带 Cookie。- 优点:现代浏览器默认支持,防御效果显著。
- 缺点:兼容性需考虑(旧浏览器可能不支持),且仅能防御 Cookie 层面的 CSRF。
6.5 增加二次验证
对敏感操作(如转账、改密)要求用户进行二次验证(密码、短信验证码、生物识别)。
- 优点:安全性高。
- 缺点:用户体验下降。
7. 最佳实践与注意点
- 组合防御:采用 CSRF Token + SameSite Cookie 是最佳实践。
- 敏感操作使用 POST:但仅用 POST 不够,因为攻击者仍可通过构造表单发起 POST 请求。
- 注意 Token 存储与传输安全:Token 应足够随机、绑定用户 Session、每次会话或请求更新。
- 防范 BREACH 攻击:避免 Token 在压缩响应中泄露。
- API 额外防护:对于前后端分离项目,可将 Token 放在请求头中,避免放在 URL 中导致泄露。
8. 总结
CSRF 攻击利用的是“网站对用户浏览器的信任”,防御的核心思路是让攻击者无法伪造包含验证信息的完整请求。现代 Web 开发中,通过框架内置的 CSRF 防护(如 Django、Spring Security、Laravel 等)可轻松实现 Token 机制,配合 SameSite Cookie 可有效消除大部分 CSRF 风险。开发者应理解底层原理,避免在自定义场景中错误配置。