前端如何配合后端实现 CSRF 的 Session 绑定验证?
我最近在做登录功能,后端说要用 Session 绑定的方式来防 CSRF,但我搞不太明白前端要怎么配合。是不是每次请求都要带一个 token?
我看后端在登录成功后往 Session 里存了个 csrf_token,那我是不是得在页面加载时把这个值取出来?可 Session 不是存在服务端的吗,前端根本拿不到啊……
难道要后端额外返回一个字段?比如登录接口同时返回用户信息和 csrfToken?像这样:
{
"user": { "id": 123 },
"csrfToken": "a1b2c3d4"
}
但这样和直接用 Cookie + SameSite 有啥区别?我试过在表单里加隐藏字段,但刷新页面 token 就失效了,体验很差。到底该怎么弄才对?
你提到的在登录接口返回用户信息的同时返回 csrfToken 这个思路是没问题的。前端拿到这个 token 之后,可以在每次提交敏感请求(比如 POST 请求)的时候,把这个 token 带上,通常放在请求头或者请求体里。
至于你说的刷新页面 token 失效,这可能是因为 token 没有持久化,每次刷新都会生成新的 token。你可以考虑把 token 存储在 localStorage 或 sessionStorage 中,这样刷新页面也不会丢失。
举个例子,假设你在登录成功后从后端获取了 csrfToken,你可以在前端这样做:
这样每次发送敏感请求时,token 都会带上,后端验证通过才能处理请求。
至于你说的 Cookie + SameSite 设置,这种方式也能有效防止 CSRF,但它依赖浏览器的支持,并且对一些旧版浏览器可能不兼容。结合使用两种方法,可以提供更好的安全保障。
插件也可以帮你简化这个过程,比如 WordPress 有很多插件专门处理安全问题,可以考虑集成这些插件来减少手动编写代码的工作量。
比如后端模板里这样注入:
或者:
前端用 axios 的话设置全局拦截器:
axios.interceptors.request.use(config => {
const token = document.querySelector('meta[name="csrf-token"]').content;
config.headers['X-CSRF-Token'] = token;
return config;
});
刷新页面不会失效,每次后端渲染都会重新从 Session 拿 token 注入。你之前 token 失效可能是用了接口返回的方式但没在每次渲染时更新。