为什么我的Double Submit Cookie防CSRF方案在登录接口失效?

UP主~红瑞 阅读 42

我在用Double Submit Cookie防CSRF时遇到奇怪的问题:其他接口都正常,但登录接口总提示”CSRF Token mismatch”。我检查了cookie设置和请求头,代码看起来没问题,但就是通不过验证…

我的流程是这样的:服务端在每次响应头里设置csrf_token到cookie,前端在请求时把cookie里的token加到请求头。但登录接口因为需要跨域预检,可能有什么特殊的地方?

这是我的前端代码片段:


document.cookie = <code>csrf_token=${response.csrfToken}; Path=/</code>; // 服务端返回的初始token

fetch('/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': document.cookie.match(/csrf_token=([^;]*)/)?.[1] || ''
  },
  body: JSON.stringify({ username: 'test', password: '123' })
})
.then(res => console.log(res))
.catch(err => console.error('CSRF验证失败:', err));

服务端日志显示请求头里的X-CSRF-Token是空的,但其他接口同样的代码却能拿到正确的token值。难道是登录页面加载时cookie还没生效?或者跨域时没带上cookie?

我来解答 赞 5 收藏
二维码
手机扫码查看
1 条解答
司空瑞君
这个问题大概率是跨域请求的预检机制导致的,我来分析一下原因。登录接口涉及到跨域,浏览器在发送POST请求之前会先发一个OPTIONS预检请求,这个预检请求是不会携带cookie的。而你的代码逻辑是在请求头里从cookie里取csrf_token,这就会导致预检阶段token为空。

服务端在处理OPTIONS请求时,应该直接返回200状态码并允许跨域,不需要验证csrf_token。但实际开发中很容易忽略这点,特别是当全局拦截器统一处理csrf校验时。

解决方法是调整服务端逻辑,给OPTIONS请求开个特例。比如这样:

if (req.method === 'OPTIONS') {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-CSRF-Token');
return res.status(200).send();
}


另外提醒一下,设置cookie时最好加上SameSite属性,避免其他潜在问题。还有就是你前端取cookie的正则表达式可以优化下,建议封装成通用方法。

顺便吐槽一句,处理跨域问题真是个体力活,我都记不清踩过多少坑了。记得多测几个浏览器,有时候Chrome能用的方案,Firefox就挂了。
点赞 3
2026-02-14 11:01