单页应用CSRF防护方案咨询:跨域Vue前端与API服务场景
优化CSRF Token实现的建议
你提到的把CSRF Token存在localStorage里确实存在不小的安全风险——因为localStorage会被同源的JS脚本直接访问,要是你的前端出现XSS漏洞,攻击者能轻松窃取这个Token,直接让CSRF防护失去意义。下面给你几个行业内更安全的标准方案:
推荐方案1:通过非HttpOnly Cookie传递CSRF Token
这是目前最主流的实现方式,步骤清晰且安全性高:
- 当用户首次访问站点(或登录成功后),后端在响应头的
Set-Cookie中设置一个非HttpOnly的Cookie(比如命名为XSRF-TOKEN),注意这个Cookie要和你的认证HttpOnly Cookie保持同域(也就是mydomain.com,适配api和前端子域的场景),同时设置合适的SameSite属性(推荐Strict或Lax,根据业务是否需要跨站请求调整),加上Secure属性确保只在HTTPS下传输。 - 前端Vue.js应用可以直接通过
document.cookie读取这个Cookie值,然后在每个需要防护的请求(比如POST/PUT/DELETE这类修改型请求)的请求头里带上它,常用的自定义头是X-XSRF-TOKEN。 - 后端接收请求时,从Cookie中取出
XSRF-TOKEN,再从请求头中取出X-XSRF-TOKEN,对比两者是否一致,一致则通过校验。
这种方案的优势:
- 借助Cookie的
SameSite属性能提供额外的CSRF防护层; - 相比localStorage,Cookie的访问限制更严格,即使出现XSS漏洞,攻击者窃取Cookie也要绕过浏览器的同源策略;
- 不需要额外的
/getCSRF接口,减少了一次无意义的网络请求。
举个Vue.js中基于axios的实现示例:
axios.interceptors.request.use(config => { // 从Cookie中提取XSRF-TOKEN const xsrfToken = document.cookie.split('; ') .find(row => row.startsWith('XSRF-TOKEN=')) ?.split('=')[1]; if (xsrfToken) { config.headers['X-XSRF-TOKEN'] = xsrfToken; } return config; });
方案2:将CSRF Token嵌入页面HTML
如果你的前端是服务端渲染(SSR)或者允许后端动态注入内容,也可以把CSRF Token直接嵌入到页面的meta标签中,比如:
<meta name="csrf-token" content="后端生成的随机唯一Token">
前端通过DOM查询获取这个值:
const xsrfToken = document.querySelector('meta[name="csrf-token"]').content;
之后同样把它放到请求头里即可。
这个方案的好处是Token不会持久化存储,每次页面加载都会生成新的Token,安全性更高;但如果是纯静态的Vue单页应用,可能需要后端在用户访问首页时动态注入这个meta标签,或者在登录接口返回Token后写入到页面中。
原方案的核心问题再梳理下
- localStorage完全暴露给同源JS,XSS攻击可以轻易窃取Token,相当于直接绕过了CSRF防护;
- 额外的
/getCSRF接口增加了系统复杂度,且如果这个接口没有做防护,攻击者也能轻松获取到Token。
最后提醒下:不管采用哪种方案,都要确保CSRF Token是随机、唯一、不可预测的,每个用户的Token应该独立,并且可以定期更新(比如每次登录后刷新Token)。
内容的提问来源于stack exchange,提问作者shamon shamsudeen
相关产品推荐
相关产品推荐

