CSRF Token 是如何工作的?
CSRF Token 是服务端生成并下发给客户端的随机值,客户端提交请求时必须携带,服务端校验通过才放行。攻击者因受同源策略限制无法读取页面中的 Token,因此无法伪造合法请求。
CSRF Token 如何防御攻击
浏览器同源策略阻止恶意页面读取目标站点的响应内容,攻击者拿不到页面里嵌入的 Token 值,构造的请求自然无法通过服务端校验。Token 防御的本质就是利用同源策略制造信息不对称——你有 Cookie 我也有,但我有你没有的 Token。
完整工作流程
服务端在会话中生成至少 128 位的加密安全随机 Token,通过表单隐藏字段或自定义请求头(如 X-CSRF-Token)下发给客户端。请求提交时客户端携带 Token,服务端比对该值与会话中存储的是否一致,一致则放行,否则拒绝。
两种主流实现模式
同步器 Token 模式——Token 存在服务端会话中,客户端通过表单隐藏字段提交。Django 的 {% csrf_token %} 和 Express 的 csurf 中间件都用这种模式。
双重提交 Cookie 模式——Token 同时写入 Cookie 和请求参数/请求头,服务端比对两者是否一致。好处是服务端不用存 Token,适合无状态架构。但必须给 Cookie 加 SameSite 属性,防止被恶意页面读取。
追问:SameSite Cookie 能否替代 CSRF Token?
不能完全替代。SameSite=Strict 会阻止所有跨站请求,从外部链接点进来直接 403,体验差;SameSite=Lax 允许顶级导航的 GET 请求,攻击面仍在。加上旧浏览器和移动端 WebView 对 SameSite 支持不一致,实际部署中推荐两者配合:SameSite 做基础防护,Token 做关键操作的强校验。
追问:SPA 中如何处理 CSRF Token?
前端通过接口获取 Token 后缓存,在 axios 拦截器里自动注入请求头。注意两个坑:会话过期或服务端返回 403 时必须重新获取 Token;不要把 Token 存 localStorage,XSS 一炸就全完了,建议用 HttpOnly Cookie 配合自定义请求头的双重提交方案。
追问:微服务架构下 Token 如何共享?
两条路:一是统一网关集中生成和校验 Token,会话状态存 Redis,各微服务从缓存读;二是用 HMAC 签名的加密 Token,服务端不存状态,直接验签就行,更适合无状态服务。选哪种取决于你的架构是否已经依赖分布式缓存。