CSRF 攻击
什么是 CSRF
跨站请求伪造(Cross-Site Request Forgery):攻击者诱导已登录用户访问恶意页面, 让用户的浏览器以用户身份向目标网站发送伪造请求。
攻击者始终看不到 cookie,他们利用的是"浏览器会自动在请求中携带 cookie"这一特性。
攻击原理
① 用户登录 bank.com,浏览器保存 session cookie
② 用户访问攻击者的 evil.com,页面内藏有:
<img src="https://bank.com/transfer?to=attacker&amount=10000">
③ 浏览器加载这个"图片"时,自动向 bank.com 发起请求
并自动携带 bank.com 的 cookie(用户毫无感知)
④ bank.com 收到请求,cookie 合法 → 以为是用户本人操作 → 执行转账
核心漏洞:服务端只凭 cookie 验证身份,而浏览器发跨站请求会自动携带 cookie。
防御方案
1. SameSite Cookie
直接在 cookie 上标注"禁止跨站携带",从根源切断攻击。
| 值 | 行为 | 适用场景 |
|---|---|---|
Strict | 任何跨站请求都不携带 cookie | 高安全需求(银行、后台) |
Lax | 跨站 GET 导航可携带,跨站 POST/嵌入不携带 | 大多数网站(浏览器默认值) |
None; Secure | 始终携带(必须配合 HTTPS) | 需要跨站登录的场景(第三方嵌入) |
Set-Cookie: sessionId=abc123; SameSite=Lax; HttpOnly; Secure
Chrome 80+ 起,未设置 SameSite 的 cookie 默认视为
Lax,大多数 CSRF 已被自动拦截。
2. CSRF Token
服务端为每个会话生成一个随机、不可预测的 token,请求时必须携带。
① 用户请求页面,服务端在 HTML 表单或 API 响应中下发 token
② 用户提交请求时,需将 token 放在请求体或自定义 Header 中
③ 服务端校验 token 是否合法
为什么有效:Same-Origin Policy 禁止跨域读取响应内容, 攻击者从 evil.com 无法读取 bank.com 返回的 token,自然无法伪造。
// 前端:在请求头中携带 token
fetch('/transfer', {
method: 'POST',
headers: { 'X-CSRF-Token': getCsrfToken() },
body: JSON.stringify({ to: 'xxx', amount: 100 })
})
3. 验证 Origin / Referer
服务端检查请求头中的 Origin 或 Referer 是否来自可信域名。
Origin: https://bank.com → 合法 ✅
Origin: https://evil.com → 拒绝 ❌
缺点:部分请求不携带 Referer(隐私模式、HTTPS→HTTP 跳转),存在误拦截风险,通常作为辅助手段。
三种防御方案对比
| 方案 | 原理 | 改造成本 | 推荐度 |
|---|---|---|---|
| SameSite Cookie | 浏览器层面禁止跨站携带 | 极低(加一个属性) | ⭐⭐⭐ 首选 |
| CSRF Token | 攻击者无法获取 token | 中等(前后端都要改) | ⭐⭐ 老项目兜底 |
| Origin 验证 | 校验请求来源域名 | 低 | ⭐ 辅助手段 |