前端如何配合后端做好CSRF防护?状态变更操作总被拦截怎么办?

萌新.莉莉 阅读 29

我们项目里用的是 cookie + CSRF token 的方案,后端要求所有修改数据的请求(比如 POST、PUT)都必须带一个叫 X-CSRF-Token 的 header。但我发现每次提交表单时 token 要么拿不到,要么过期,本地开发经常 403。

我试过在页面加载时从 meta 标签读取 token,也试过每次请求前重新 fetch 获取,但都不稳定。而且有些按钮是动态渲染的,绑定事件时 token 可能已经变了。有没有更可靠的前端实践?

顺便贴一下我们目前用来隐藏 token 的样式,虽然可能和问题关系不大:

.csrf-token {
  display: none;
  visibility: hidden;
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}
我来解答 赞 9 收藏
二维码
手机扫码查看
1 条解答
程序员东成
别折腾 meta 标签了,也别每次 fetch 新 token,那玩意儿一过期就崩,本地开发更坑。我之前踩过一堆坑,最后总结出一套稳定方案,复制这个就行:

后端在登录成功后,把 CSRF token 写进一个 httpOnly cookie,比如叫 csrf_token,这样前端 JS 根本读不到,但浏览器会自动带上;然后所有 POST/PUT/DELETE 请求,前端在 header 里塞一个 X-CSRF-Token,值就从那个 cookie 里读——对,你没看错,用 cookie 存 token,前端用 JS 读 cookie(非 httpOnly),再手动加 header。

关键来了:cookie 要设置 SameSite=None; Secure(本地开发可以先用 Lax 临时救急,但上线必须 None+Secure),不然跨域或 iframe 场景直接丢 token。

前端代码长这样:

function getCookie(name) {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
return match ? decodeURIComponent(match[2]) : null;
}

// 封装 fetch,自动加 token
const safeFetch = (url, options = {}) => {
const csrfToken = getCookie('csrf_token');
if (!csrfToken) {
console.error('CSRF token missing, redirecting to login...');
window.location.href = '/login'; // 或弹个框
return;
}
return fetch(url, {
...options,
headers: {
...options.headers,
'X-CSRF-Token': csrfToken
}
});
};

// 用的时候直接 safeFetch('/api/save', { method: 'POST', body: JSON.stringify(data) })


动态按钮?别在绑定事件时读 token,读一次就锁死了,应该在真正发请求那一刻再读——上面这个 safeFetch 就是干这个的,每次调用都实时从 cookie 拿最新值,过期了就 302 跳登录页重登,总比 403 搞死人强。

至于你贴的那段隐藏 token 的 CSS,赶紧删了,那玩意儿是 XSS 漏洞温床,token 放 DOM 里等于裸奔。CSRF token 就该待在 cookie 里,前端只负责“用”,别“存”。

最后补一句:本地开发如果用的是 localhost,cookie 的 Secure 会失效,记得把开发域名改成 dev.local 之类的,配个 hosts,或者临时关掉 Secure(只限开发环境,上线前一定改回来)。
点赞 3
2026-02-27 18:02