CSRF 攻击的防御方案
更新: 5/24/2026 字数: 0 字 时长: 0 分钟
防御 CSRF 的核心思路只有一个:让正规站点能够识别"这个请求到底是不是用户本人在本站点上主动发起的"。围绕这个目标,业界形成了从服务端到客户端、从协议层到业务层的多重防御体系。
一、服务端防御(核心手段)
1. CSRF Token(同步令牌模式,最主流方案)
原理:服务端为每个用户会话生成一个不可预测的随机令牌,要求所有敏感请求必须额外携带这个令牌,且令牌不能放在 Cookie 中。
完整流程:
- 用户访问表单页面时,服务端在 HTML 中嵌入一个隐藏字段
<input type="hidden" name="csrf_token" value="随机字符串">,同时把该 Token 存入服务端 Session。 - 用户提交请求时,浏览器把 Token 一并发送给服务端。
- 服务端比对"请求中的 Token"与"Session 中的 Token",一致才放行。
为什么有效:恶意站点由于同源策略限制,无法读取正规站点页面中的 Token,伪造的请求里没有 Token 或 Token 错误,直接被拒绝。
注意事项:
- Token 必须足够随机(使用密码学安全的随机数生成器)。
- Token 不能放在 URL 中(易通过 Referer 泄露)。
- 一次性 Token 安全性更高,但会话级 Token 实现更简单,按场景选择。
2. Double Submit Cookie(双重提交 Cookie)
原理:服务端生成随机值,同时写入 Cookie 和返回给前端,前端在提交请求时把该值放入请求头或表单参数。服务端校验"Cookie 中的值"与"请求参数中的值"是否一致。
为什么有效:恶意站点虽然能让浏览器自动带上 Cookie,但读不到 Cookie 的内容(受同源策略保护),因此无法在请求参数中放入匹配值。
适用场景:无 Session 的分布式系统、纯前后端分离架构,无需服务端存储状态。
注意事项:需配合 Secure、HttpOnly 之外的合适 Cookie 属性,避免子域被攻击者控制后绕过。
3. SameSite Cookie 属性(现代浏览器原生防御)
原理:通过给 Cookie 设置 SameSite 属性,告诉浏览器"跨站请求时是否携带该 Cookie"。
| 取值 | 行为 | 防御效果 |
|---|---|---|
Strict | 任何跨站请求都不携带 Cookie | 最强,但用户体验差(从外站点跳转进来会丢失登录态) |
Lax | 仅在顶级导航的 GET 请求(如点击链接)携带,跨站的 POST/iframe/img 等不携带 | 当前主流浏览器的默认值,平衡安全与体验 |
None | 任何跨站请求都携带(必须同时设置 Secure) | 无 CSRF 防护,仅在确实需要跨站 Cookie 时使用 |
推荐做法:敏感 Cookie 统一设置 SameSite=Lax 或 Strict,并配合 Secure、HttpOnly。
注意:SameSite 是纵深防御,不能完全替代 CSRF Token。老旧浏览器不支持,且
Lax模式下仍可能被 GET 型 CSRF 利用。
4. 校验 Referer / Origin 请求头
原理:HTTP 请求头中的 Origin 和 Referer 标识了请求来源页面,服务端校验来源是否为本站合法域名。
- Origin:优先校验,POST/PUT/DELETE 等请求通常会自动携带,且不包含路径,更适合做来源判断。
- Referer:作为兜底校验。
局限性:
- 用户/浏览器可能因隐私设置禁用 Referer。
- 某些场景下 Referer 不会被发送(如 HTTPS → HTTP 跳转)。
- 仅作为辅助校验,不建议作为唯一防线。
5. 关键操作二次验证
对高敏感操作(转账、改密码、删除账号等),强制要求用户额外输入:
- 短信验证码 / 邮箱验证码
- 图形验证码
- 二次输入登录密码
- 生物识别 / U 盾 / 硬件密钥
为什么有效:即使 CSRF 请求成功发出,攻击者无法获取这些动态信息,操作仍会被阻断。这是金融级场景的最后一道防线。
二、规范层面的防御
6. 严格遵循 HTTP 方法语义
- GET 请求只用于查询,绝不执行任何状态变更操作(不要做转账、删除、修改)。
- 状态变更操作必须使用 POST / PUT / DELETE。
为什么重要:GET 型 CSRF 只要一张 <img> 就能触发,门槛极低;强制使用非 GET 方法后,攻击者必须构造表单或 AJAX,配合 SameSite=Lax 即可大幅减少攻击面。
7. 自定义请求头 + CORS 校验
要求所有 AJAX 请求携带自定义请求头(如 X-Requested-With: XMLHttpRequest 或 X-CSRF-Token)。
为什么有效:浏览器对带自定义头的跨域请求会触发 CORS 预检(Preflight),恶意站点没有正规站点的 CORS 许可,预检直接失败,真实请求根本不会发出。
三、用户侧建议(辅助)
- 使用敏感网站后及时登出,缩短登录态有效窗口。
- 不要在登录敏感账户的浏览器中随意点击不明链接。
- 使用浏览器隐私模式 / 多账号容器隔离不同站点的会话。
- 保持浏览器更新,启用现代浏览器的默认安全策略。
四、推荐的纵深防御组合
单一手段都有局限,生产环境建议组合使用:
| 层级 | 防御措施 | 优先级 |
|---|---|---|
| 协议层 | SameSite=Lax/Strict + Secure + HttpOnly Cookie | 必选 |
| 应用层 | CSRF Token(或 Double Submit Cookie) | 必选 |
| 接口层 | 校验 Origin / Referer | 推荐 |
| 规范层 | 严格区分 GET 与状态变更方法 | 必选 |
| 业务层 | 关键操作二次验证(验证码 / 密码 / OTP) | 高敏感场景必选 |
一句话总结
防御 CSRF 的本质,是让"伪造的请求"无法通过身份与来源的双重校验。 Cookie 解决"你是谁",Token / SameSite / Origin 解决"这个请求是不是你真的想发"——两者缺一不可。