Spring Cloud Gateway启用CSRF后响应未返回CSRF令牌问题
问题根因
你的配置存在3个核心问题,直接导致CSRF令牌不返回、GET请求异常报错:
- 重复调用了两次
.csrf()配置,第一次写的.requireCsrfProtectionMatcher豁免规则会被第二次的CSRF自定义配置完全覆盖,等于你配置的登录接口、静态资源豁免规则根本没有生效 - Spring WebFlux响应式栈下,
CookieServerCsrfTokenRepository不会自动将CSRF令牌写入响应Cookie。CsrfToken的生成、写入逻辑封装在冷流Mono<CsrfToken>中,必须显式订阅这个流才会触发实际的Cookie写入逻辑,这是响应式编程的特性,也是WebFlux集成CSRF最常见的坑 - 路径匹配规则存在漏洞:你写的
/*仅匹配根路径下一级路径,无法匹配多级路由;且重复配置覆盖规则后,CSRF会退回错误的匹配逻辑,把GET请求也纳入校验范围
修复方案
- 合并CSRF配置,不要重复调用
.csrf(),修正路径匹配规则 - 添加CSRF过滤器,显式订阅CsrfToken流触发Cookie写入
- 修正路径匹配规则,避免过度豁免或者漏匹配
完整的SecurityWebFilterChain配置参考:
@Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // 其他原有配置(鉴权、跨域等)保持不变 .csrf(csrf -> csrf // 配置Cookie存储CSRF令牌,关闭httpOnly允许前端JS读取 .csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()) // 配置豁免路径:匹配到以下路径时跳过CSRF校验 .requireCsrfProtectionMatcher( new NegatedServerWebExchangeMatcher( pathMatchers( "/i18n/**", // 原/*改为/**匹配i18n下所有多级路径 "/assets/**", "/service/webapi/login", "/*.html", "/favicon.ico" ) ) ) ); // 关键配置:添加过滤器订阅CsrfToken流,触发Cookie写入响应 http.addFilterAfter((exchange, chain) -> { Mono<CsrfToken> csrfToken = exchange.getAttribute(CsrfToken.class.getName()); return csrfToken != null ? csrfToken.then(chain.filter(exchange)) : chain.filter(exchange); }, SecurityWebFiltersOrder.CSRF); return http.build(); }
配置完成后,第一个任意合法请求到达服务端后,响应就会自动携带XSRF-TOKEN的Cookie。Angular框架会自动读取这个Cookie,在后续非GET请求中自动把令牌放到X-XSRF-TOKEN请求头中,不需要额外做前端适配。
关于GET请求是否需要CSRF校验
- 按照CSRF防护的标准规范,幂等请求(GET、HEAD、TRACE、OPTIONS)默认不需要做CSRF令牌校验。这类请求按照HTTP规范不应该修改服务端存储的状态,本身不存在CSRF攻击风险。
- 你当前GET请求报
an expected csrf token cannot be found错误,完全是因为之前重复配置CSRF导致匹配规则失效,GET请求被错误纳入校验范围导致的,修复上述配置后该问题会自动消失。 - 如果你存在不符合REST规范的GET接口(即GET请求会修改服务端数据),才需要单独把这类接口加入CSRF校验范围,正常业务场景不需要给GET请求加CSRF校验。
内容的提问来源于stack exchange,提问作者manjosh
相关产品推荐
相关产品推荐

