Spring Boot如何验证Cookie中CSRF Token?修改Cookie值未拦截?
问题分析与解决方案
这种情况正常吗?
不正常。正常配置下,修改Cookie中的XSRF-TOKEN值后,后端应该拦截非法请求——因为Angular会自动将Cookie中的值同步到X-XSRF-TOKEN请求头,此时请求头的值与服务器预期的Token不匹配,验证失败。
为什么你的配置没拦截非法请求?
Spring Security的CookieCsrfTokenRepository默认是通过对比请求头X-XSRF-TOKEN与CookieXSRF-TOKEN的值完成验证的,核心逻辑是跨站请求无法读取当前站点的Cookie,也就无法构造正确的请求头。
你的问题出在CsrfTokenRequestHandler的配置错误:你只使用了XorCsrfTokenRequestAttributeHandler的handle方法,却没有利用它的resolveCsrfTokenValue方法处理Token的解密逻辑。XorCsrfTokenRequestAttributeHandler会对Token做异或编码防止日志泄露,若只调用handle方法,后端无法正确解析请求头中的Token,导致验证逻辑直接失效。
修复步骤
1. 修正CsrfTokenRequestHandler配置
将原来的分段配置改为直接使用完整的XorCsrfTokenRequestAttributeHandler实例:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse(); // 直接实例化完整的XorCsrfTokenRequestAttributeHandler作为请求处理器 XorCsrfTokenRequestAttributeHandler requestHandler = new XorCsrfTokenRequestAttributeHandler(); requestHandler.setCsrfRequestAttributeName(null); // 禁用延迟加载Token http .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .formLogin((login) -> login .successHandler((request, response, authentication) -> response.setStatus(200)) ) .logout((logout) -> logout .logoutSuccessHandler(new CsrfTokenAwareLogoutSuccessHandler(tokenRepository)) ) .cors(Customizer.withDefaults()) .exceptionHandling((exceptions) -> exceptions .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) ) .csrf((csrf) -> csrf .csrfTokenRepository(tokenRepository) .csrfTokenRequestHandler(requestHandler) // 使用完整的处理器 ); return http.build(); }
2. 验证CSRF防护是否生效
- 移除请求中的
X-XSRF-TOKEN头,发起POST请求,若返回403 Forbidden,说明验证逻辑已生效。 - 修改Cookie中的
XSRF-TOKEN值,发起POST请求,若返回403 Forbidden,说明验证逻辑正常工作。
3. 确认前端Token传递逻辑
用浏览器开发者工具检查请求:
- Cookie中包含
XSRF-TOKEN - POST/PUT/DELETE请求的请求头中包含
X-XSRF-TOKEN,且值与Cookie中的XSRF-TOKEN一致
其他疑问解答
- 是否可以随意添加X-XSRF-TOKEN发起请求?:不行。只有服务器生成的有效Token才能通过验证,随意填写的Token值与服务器存储的Token不匹配,会被拦截。
- 如何确保CSRF保护正确?:
- 确保所有非GET/HEAD/OPTIONS的请求都携带
X-XSRF-TOKEN头 - 保持Cookie的
HttpOnly属性为false(已在你的配置中通过withHttpOnlyFalse()实现),让前端能读取XSRF-TOKEN - 验证修改Cookie或移除请求头后,请求会被拦截
- 确保所有非GET/HEAD/OPTIONS的请求都携带
内容的提问来源于stack exchange,提问作者Francis
相关产品推荐
相关产品推荐

