客户端XSRF-TOKEN与服务器端校验问题排查及合理性咨询
解答
1. 为什么X-XSRF-TOKEN请求头偶尔为null?
结合实际项目经验,这种情况通常由以下几个原因导致:
- 前端未正确处理令牌传递:Spring Security默认会把CSRF令牌存到名为
XSRF-TOKEN的Cookie中,前端需要主动读取这个Cookie,并在后续的非GET请求中把令牌放到X-XSRF-TOKEN请求头里。如果前端是单页应用,可能没在登录成功后自动配置这个逻辑,或者某些异步请求遗漏了带令牌。 - 请求类型或路径不需要校验:按照CSRF防护的默认规则,GET、HEAD这类不会修改服务器状态的请求,前端可能没带令牌,但你的过滤器如果拦截了所有请求并强制校验,就会出现头为null的情况;另外静态资源(如JS、CSS)请求通常不需要校验,若被过滤器拦截也会出现这个问题。
- Cookie相关的跨域或存储问题:如果是跨域场景,Cookie的
SameSite属性设置过严(比如设为Strict但请求是跨域发起的),浏览器会拒绝携带Cookie,前端自然拿不到令牌;还有Cookie过期、被浏览器清理,也会导致前端无法获取令牌进而无法在请求头中携带。 - 过滤器执行顺序问题:你的代码里是
addFilterAfter(csrfHeaderFilter(), CsrfFilter.class),意味着Spring Security自带的CsrfFilter会先执行。如果默认过滤器已经处理了令牌逻辑,或者在某些场景下清空了相关请求头,就可能导致你的自定义过滤器拿不到值。
2. 如何确定哪些请求需要校验CSRF令牌?
按照OWASP的最佳实践,所有会修改服务器状态的请求都必须做CSRF校验,具体可以这样划分:
- ✅ 需要校验的请求方法:POST、PUT、DELETE、PATCH(这些方法会创建、修改或删除数据)
- ❌ 不需要校验的请求方法:GET、HEAD、OPTIONS、TRACE(这些方法是"安全"的,不会改变服务器上的数据)
- 特殊路径:登录请求(比如你的
/authenticate)Spring Security默认会处理CSRF校验,但如果是自定义登录逻辑也要注意;另外静态资源路径(如/static/**、/css/**)可以直接放行,无需校验。
在Spring Security中,你可以通过csrf().ignoringAntMatchers()来指定不需要校验的路径,示例代码如下:
.csrf() .csrfTokenRepository(csrfTokenRepository()) .ignoringAntMatchers("/authenticate", "/static/**")
3. 这种自定义过滤器校验CSRF的方式是否可行?
其实不推荐完全自定义校验逻辑,原因如下:
Spring Security已经提供了成熟的CsrfFilter来处理CSRF校验,它已经考虑了会话过期、令牌过期、跨域场景等各种边界情况,自定义过滤器很容易遗漏这些细节,导致防护出现漏洞。
如果你的需求是要从请求头获取令牌(而不是默认的请求参数),其实无需自定义过滤器——Spring Security本身就支持这种方式。比如使用CookieCsrfTokenRepository.withHttpOnlyFalse(),它会把令牌存到可被前端读取的Cookie中,前端只需把令牌放到X-XSRF-TOKEN请求头,默认的CsrfFilter就会自动校验这个头。
如果一定要自定义过滤器,建议把过滤器放在CsrfFilter之前(用addFilterBefore),并且只针对需要校验的请求方法(POST/PUT等)进行处理,同时确保和Spring Security的会话管理逻辑兼容,避免出现令牌获取不到的问题。
内容的提问来源于stack exchange,提问作者Zmur
相关产品推荐
相关产品推荐

