JSON 格式的 CSRF 如何防御
1. 使用 CSRF Token
这是最常见和最可靠的防御方法
工作原理:
- 服务器在用户登录后,生成一个随机、唯一的 CSRF Token,并将其存储在会话中或某个安全的地方(如
sessionStorage
) - 服务器将 Token 发送给客户端
- 客户端在发起任何敏感操作的请求时,都必须将这个 Token 放在HTTP 请求头或 POST 请求体中
- 服务器接收到请求后,会验证请求中的 Token 是否与服务器上存储的 Token 相匹配。如果不匹配,则拒绝请求
- 服务器在用户登录后,生成一个随机、唯一的 CSRF Token,并将其存储在会话中或某个安全的地方(如
在 JSON 请求中的实践: 客户端的 JavaScript 代码在发起 POST 请求时,将 Token 放在一个自定义的 HTTP 头中,例如
X-CSRF-TOKEN
fetch('https://your-api.com/transfer', { method: 'POST', body: JSON.stringify({ to: 'attacker', amount: 1000 }), headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': 'your-generated-token' } });
防御原理:攻击者无法从
your-api.com
域获取有效的 CSRF Token。由于同源策略的限制,恶意网站的 JavaScript 无法读取你的 API 返回的 HTML 或 JSON 数据,因此无法获取 CSRF Token。此外,即使是简单请求,自定义的 HTTP 头也会触发预检请求,同样会被 CORS 机制拦截
2. 使用 SameSite Cookie
前面我们讨论过 SameSite
属性。在 JSON API 的场景中,SameSite=Lax
同样是有效的防御
工作原理: 将你的会话 Cookie 的
SameSite
属性设置为Lax
或Strict
。当攻击者从恶意网站发起 POST 请求时,浏览器不会携带这个会话 Cookie。服务器在验证请求时,因为没有会话信息,会直接拒绝请求Set-Cookie: sessionid=xxxx; SameSite=Lax; Secure; HttpOnly
最佳实践:
SameSite=Strict
:提供了最强的防御,但可能影响用户体验SameSite=Lax
:在大多数情况下提供了足够的保护,同时不影响用户从其他网站通过 GET 链接跳转到你的网站
3. 验证 Referer 或 Origin 头
这种方法是辅助性的,但可以提供额外的安全层
- 工作原理: 服务器检查请求头中的
Referer
或Origin
字段,验证请求的来源是否为你的合法域名Referer
:表示发起请求的 URLOrigin
:表示请求的来源域,通常用于 CORS 预检请求中
- 局限性:
Referer
字段可以被一些浏览器或代理软件修改或删除- 这不是一个完全可靠的防御方法,应作为辅助手段而非主要策略