CSRF防护中,如何安全地刷新验证Token而不暴露在URL中?

诸葛宁蒙 阅读 109

最近在做CSRF防护时遇到个难题,我用了隐藏字段+请求头双验证的方案。但用户长时间在线后,原来的Token过期导致部分AJAX请求开始报403错误。

尝试过在每次请求前手动调用API刷新Token,但发现新Token只能通过Cookie返回,如果用JavaScript读取HTTP Only的Cookie就会报错。如果改成普通Cookie存储,又担心被XSS窃取。

现在页面结构是Vue单页应用,后端用Spring Security。有人建议在每个响应头里带上新的Token,但这样每次都要处理响应拦截,有没有更好的方式在保持Token安全的同时实现自动刷新?

我来解答 赞 7 收藏
二维码
手机扫码查看
2 条解答
诸葛广利
当时我也卡在这,折腾了快两天。你现在的方案其实方向是对的,但关键在于Token怎么传回来。

直接说结论:别指望从HTTP Only Cookie里拿Token,根本行不通。正确做法是在每次后端返回响应的时候,通过自定义响应头把新的CSRF Token塞进去,比如叫 X-CSRF-TOKEN。这个值你在拦截器里更新到Vue的全局状态或者axios默认头就行。

具体流程是这样:

后端在每次请求处理完后,不管是不是POST,都生成一个新的Token(保持有效期滚动),然后把这个Token写进响应头,同时存进服务端session或Redis做关联。原来的那个HTTP Only Cookie只用来做服务端校验,不给前端读。

前端用axios的话,写个响应拦截器,拿到这个头里的Token之后,更新到下一次请求要用的地方,比如存到内存变量,再设置到下次请求的头里。这样URL和Cookie都不暴露Token,XSS也拿不到。

有个坑我踩过:别在拦截器里异步刷新Token,会导致并发请求带着旧Token发出去,结果部分请求403。应该让第一个失败请求触发刷新,后续请求排队等新Token回来再重发。

Spring Security这边可以用一个过滤器,在doFilter最后阶段加响应头,Token生成用CsrfTokenRepository那一套机制就行。Vue那边维护一个待刷新的Promise队列,刷新期间的新请求先挂起。

这套机制上线半年了,没再出现过因为Token过期导致的批量报错。
点赞 4
2026-02-10 16:02
Des.艳花
我的做法是把新Token放在响应头里,但不是随便哪个头,用一个自定义响应头比如 X-CSRF-TOKEN,后端每次处理完请求后都生成一个新的Token塞进去。前端在axios的响应拦截器里统一处理,拿到新的Token存到内存或者Vuex里,后续请求再通过请求头带出去。

关键点在于后端要配合:Spring Security可以配个过滤器,每次请求结束后检查有没有刷新Token的需求,有就往响应头写新的Token,同时更新Cookie里的值(设成HttpOnly)。这样就算XSS拿不到Cookie,CSRF也搞不了事,因为攻击者伪造的请求没法带上正确的请求头。

前端这块其实不难,axios.interceptors.response.use的时候判断下状态码是不是200系列,然后从res.headers['x-csrf-token']取值,保存下来就行。注意别存localStorage,直接放内存或Vuex,页面刷新再通过服务端渲染或者初始化接口拉一次就行。

我们项目就这么跑了一年多,没出过问题。唯一要注意的是第一次加载页面时得有个初始Token,可以在页面render的时候内联一个script把token注入window对象,或者用个初始化API提前拿。
点赞 3
2026-02-08 20:09