CSRF 跨站请求伪造:原理、利用方式与现代防御策略

在 Web 安全领域,跨站请求伪造(Cross-Site Request Forgery,CSRF)是一种极为常见且危害巨大的攻击方式。尽管近年来随着现代框架的普及,CSRF 的防御手段日趋成熟,但理解其底层原理和演变仍然是从业者的必修课。本文将系统性地剖析 CSRF 的工作机制、典型利用手法以及当前主流的防御策略。

一、什么是 CSRF

CSRF 的核心思想可以用一句话概括:攻击者诱导已登录的用户,在不知情的情况下向目标站点发送一个恶意请求。

这里的关键在于“已登录”。浏览器在访问某个站点时,会自动携带该站点下的 Cookie(包括 Session ID)。攻击者正是利用了浏览器的这一自动携带机制,让受害者的浏览器“代替”攻击者发起请求。

用一个生活化的比喻:你拿着公司门禁卡进入大楼后,有人趁你不注意,拿着你的手去刷了门禁,打开了本不该打开的门。门禁系统只认卡,不认“刷卡的意图”。

二、CSRF 的攻击原理

要理解 CSRF,需要先理解浏览器 Cookie 的同源策略例外。Cookie 的作用域由域名决定,而非由发起请求的页面决定。这意味着:

  1. 用户登录 bank.com,浏览器保存了 bank.com 的 Session Cookie。
  2. 用户在同一浏览器中访问了攻击者的页面 evil.com
  3. evil.com 的页面中包含一个向 bank.com/transfer 发起的请求。
  4. 浏览器在发送该请求时,自动附带上 bank.com 的 Cookie。
  5. bank.com 的服务端收到请求,验证 Cookie 有效,执行转账操作。

整个过程中,用户没有进行任何主动操作,甚至可能根本没有意识到请求的发生。

三、常见的利用方式

3.1 GET 型 CSRF

最简单的形式是通过一个图片标签或链接发起 GET 请求:

<img src="https://bank.com/transfer?to=attacker&amount=10000" />

当受害者打开包含该标签的页面时,浏览器会自动加载图片,从而触发转账请求。这种攻击的隐蔽性在于图片可以设置为 1×1 像素,用户完全看不到任何异常。

3.2 POST 型 CSRF

对于只接受 POST 请求的接口,攻击者可以构造一个自动提交的隐藏表单:

<form action="https://bank.com/transfer" method="POST" id="csrf-form">
  <input type="hidden" name="to" value="attacker" />
  <input type="hidden" name="amount" value="10000" />
</form>
<script>document.getElementById('csrf-form').submit();</script>

用户打开页面后,表单自动提交,攻击完成。

3.3 JSON 型 CSRF

当接口接受 application/json 格式时,传统的表单提交无法直接构造该 Content-Type。但攻击者可以通过 fetch 配合 text/plain 绕过部分校验,或者利用 Flash 等历史遗留技术。虽然现代浏览器对跨域 fetch 有严格限制,但如果服务端未严格校验 Content-Type,仍然存在风险。

3.4 结合 XSS 的进阶利用

如果目标站点存在 XSS 漏洞,攻击者可以直接在页面内发起请求,此时连 CSRF Token 都可以被读取,CSRF 防御形同虚设。这也是为什么 XSS 通常被视为比 CSRF 更严重的漏洞。

四、为什么 CSRF 至今仍然危险

很多人认为“上了 HTTPS 就安全了”或“用了 Vue/React 就没问题了”,但事实并非如此:

  • HTTPS 不防 CSRF:HTTPS 只保证传输加密,不验证请求意图。
  • 前端框架不自动防御:React、Vue 等框架只处理 UI 层,请求仍然由浏览器自动携带 Cookie。
  • API 优先架构扩大了攻击面:越来越多的应用使用无状态 API,如果仅依赖 Cookie 鉴权,CSRF 风险反而更高。
  • 用户习惯难以改变:用户往往在多个标签页中同时登录多个站点,为攻击者提供了天然的“已登录”环境。

五、现代防御策略

5.1 CSRF Token

最经典且仍然有效的方案。服务端在渲染表单时生成一个随机 Token,嵌入表单隐藏字段或自定义请求头中。服务端在处理请求时校验 Token 是否匹配。

关键要点:

  • Token 必须与用户会话绑定。
  • Token 必须使用密码学安全的随机数生成器。
  • 对于前后端分离架构,可以通过 X-CSRF-Token 请求头传递。

5.2 SameSite Cookie 属性

这是目前最推荐的“第一道防线”。通过设置 Cookie 的 SameSite 属性,可以控制 Cookie 在跨站请求中是否发送:

  • SameSite=Strict:完全禁止跨站携带 Cookie,安全性最高,但可能影响从外部链接跳转的体验。
  • SameSite=Lax:允许顶级导航的 GET 请求携带 Cookie,阻止 POST 等跨站请求。这是现代浏览器的默认值。
  • SameSite=None:允许跨站携带,但必须同时设置 Secure,适用于需要跨站嵌入的场景(如 iframe)。

5.3 验证 Origin 和 Referer

服务端可以检查请求头中的 OriginReferer,确认请求是否来自可信来源。这种方法实现简单,但需要注意:

  • 部分隐私工具会剥离 Referer。
  • 应优先检查 Origin,因为它在跨域请求中更可靠。
  • 需要维护可信域名白名单。

5.4 自定义请求头

对于 AJAX 请求,要求客户端携带一个自定义请求头(如 X-Requested-With: XMLHttpRequest)。由于浏览器同源策略的限制,跨域请求无法自定义请求头(除非服务端明确允许 CORS),因此可以作为一种轻量级防御手段。

5.5 双重提交 Cookie

将 CSRF Token 同时存储在 Cookie 和请求参数中,服务端比较两者是否一致。这种方案无需服务端存储 Token,适合无状态架构,但需要确保子域名不会覆盖 Cookie。

5.6 关键操作二次验证

对于转账、修改密码、删除账户等敏感操作,强制要求用户重新输入密码或进行 MFA 验证。这是最后一道防线,也是最可靠的。

六、防御策略的组合建议

单一防御手段往往存在绕过风险,推荐采用纵深防御策略:

  1. 默认设置 SameSite=Lax,对敏感 Cookie 使用 SameSite=Strict
  2. 对所有状态变更请求实施 CSRF Token 校验
  3. 校验 Origin,作为辅助手段。
  4. 敏感操作要求二次认证
  5. 定期进行安全测试,包括自动化扫描和手动渗透。

七、总结

CSRF 的本质是浏览器自动携带凭据的机制被恶意利用。虽然现代浏览器和框架提供了更多防御工具,但 CSRF 并未消失,而是随着架构演变呈现出新的形态。开发者需要理解其原理,而不是机械地复制防御代码。只有将 SameSite Cookie、CSRF Token、Origin 校验和二次验证结合起来,才能构建真正健壮的防御体系。

安全从来不是某一个措施的结果,而是多个层次协同作用的产物。

未经允许不得转载:任鹏个人博客 » CSRF 跨站请求伪造:原理、利用方式与现代防御策略

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏