为什么我的Double Submit Cookie防CSRF方案在登录接口失效?
我在用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?
服务端在处理OPTIONS请求时,应该直接返回200状态码并允许跨域,不需要验证csrf_token。但实际开发中很容易忽略这点,特别是当全局拦截器统一处理csrf校验时。
解决方法是调整服务端逻辑,给OPTIONS请求开个特例。比如这样:
另外提醒一下,设置cookie时最好加上SameSite属性,避免其他潜在问题。还有就是你前端取cookie的正则表达式可以优化下,建议封装成通用方法。
顺便吐槽一句,处理跨域问题真是个体力活,我都记不清踩过多少坑了。记得多测几个浏览器,有时候Chrome能用的方案,Firefox就挂了。