0

Spring Cloud Gateway keeps rejecting my csrf token even though request header "X-XSRF-TOKEN" and "XSRF-TOKEN" cookie are correctly set as you can see here:

enter image description here

This is the Spring Cloud Gateway Security configuration:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
    @Autowired
    private ReactiveClientRegistrationRepository clientRegistrationRepository;

    @Bean
    SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {

        CorsConfiguration cors_config = new CorsConfiguration(); //Setting cors config
        cors_config.setAllowCredentials(true);
        cors_config.applyPermitDefaultValues();
        cors_config.setAllowedOrigins(Arrays.asList("http://localhost:3000", "null"));
        cors_config.setAllowedMethods(List.of("GET", "POST", "OPTIONS", "DELETE"));
        cors_config.setAllowedHeaders(List.of("*"));


        http.cors().configurationSource(source -> cors_config)
                .and()
                .authorizeExchange(exchanges -> exchanges.anyExchange().authenticated())
                .oauth2Login()//Setting Oauth2Login
                .authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("http://localhost:3000/")).and()
                .logout(logout -> logout //Setting Oauth2Logout
                        .logoutHandler(logoutHandler())
                        .logoutSuccessHandler(oidcLogoutSuccessHandler()))
                .csrf(csrf -> csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())); //Enabling csrf (all post/patch/put/... requests will need a csrf token in X-XSRF-TOKEN header
        return http.build();
    }


    private ServerLogoutSuccessHandler oidcLogoutSuccessHandler() {
        OidcClientInitiatedServerLogoutSuccessHandler oidcLogoutSuccessHandler =
                new OidcClientInitiatedServerLogoutSuccessHandler(this.clientRegistrationRepository);
        // Sets the location that the End-User's User Agent will be redirected to
        // after the logout has been performed at the Provider
        oidcLogoutSuccessHandler.setPostLogoutRedirectUri("http://localhost:8090/oauth2/authorization/spring-gateway-client");
        return oidcLogoutSuccessHandler;
    }

    private DelegatingServerLogoutHandler logoutHandler() {
        //Invalidate session on logout
        return new DelegatingServerLogoutHandler(
                new SecurityContextServerLogoutHandler(), new WebSessionServerLogoutHandler());
    }


}

Filter:

@Component
public class C {

    @Bean
    public WebFilter addCsrfTokenFilter() {
        return (exchange, next) -> Mono.just(exchange)
                .flatMap(ex -> ex.<Mono<CsrfToken>>getAttribute(CsrfToken.class.getName()))
                .doOnNext(ex -> {
                })
                .then(next.filter(exchange));
    }
}

I don't really know how to solve this.

Centuri0n
  • 59
  • 1
  • 6
  • I'm not sure about your conf. Do you intend to disable CSRF protection (as per 3rd line of http config) or enable it (as per last line)? – ch4mp Feb 11 '23 at 01:17
  • Yes, the "csrf.disable()" line should be omitted. However, request is still failing with 403 forbidden and "invalid csrf token" error message.. – Centuri0n Feb 11 '23 at 07:31
  • "By default, the CookieServerCsrfTokenRepository writes to a cookie named XSRF-TOKEN and read its from a header named X-XSRF-TOKEN or the HTTP _csrf parameter." says here: https://docs.spring.io/spring-security/reference/reactive/exploits/csrf.html. My requests contain both cookie XSRF-TOKEN and header X-XSRF-TOKEN but Gateway does not accept it, perhaps my Oauth2 configuration is interfering somehow? – Centuri0n Feb 11 '23 at 08:26
  • Perhaps you need to add the `WebFilter` to the `SecurityWebFilterChain` with `http.addFilterBefore(addCsrfTokenFilter(), SecurityWebFiltersOrder.CSRF)`? – Alex R Feb 11 '23 at 09:02
  • @Alex R, Fails with: "The mapper returned a null Publisher" – Centuri0n Feb 11 '23 at 09:33
  • Do you import the correct `CsrfToken` class? There are two with the same name, one under `org.springframework.security.web.server.csrf.CsrfToken` and one under `org.springframework.security.web.csrf.CsrfToken`. You need to import the first one for reactive apps. – Alex R Feb 11 '23 at 10:58
  • I had kind of a similar problem some while ago, my `WebFilter` implementation now looks like this: `Mono token = exchange.getAttribute(CsrfToken.class.getName()); return (token != null) ? token.flatMap(t -> chain.filter(exchange)) : chain.filter(exchange);` If that's not working for you, I've got no idea, sorry. – Alex R Feb 11 '23 at 11:02
  • Yes, the imports are correct. – Centuri0n Feb 11 '23 at 11:07
  • Can anybody please help? – Centuri0n Feb 14 '23 at 11:58
  • 3
    Although i have the same issue i can point you in a direction so you may find an answer i did not. Here is a SO answer by @steve-riesenberg https://stackoverflow.com/questions/74447118/csrf-protection-not-working-with-spring-security-6 which proposes a solution that did not work for me (spring boot 3.0, webflux setup) There is also this documentation https://docs.spring.io/spring-security/reference/5.8/migration/reactive.html#reactive-csrf-breach-opt-out which does not work. Everything i have tried so far results in Invalid CSRF Token – SeaBiscuit Feb 18 '23 at 22:22
  • My angular app sends X-XSRF-TOKEN header as well as XSRF-TOKEN=8-LTmcuEAqh9glY1Ds9OGFX7bBAkPldtXxc53JKiQuI55RqIwICyq660MMxQsmAMOuJ6IW3MQXFCD2FAZyda6aDAdNEK0nm7 cookie. – SeaBiscuit Feb 18 '23 at 22:23
  • The solution provided in the spring-security doc `Configure CsrfToken BREACH Protection to validate raw tokens` worked for me. – Centuri0n Feb 18 '23 at 22:57
  • I have found my mistake. So silly. I was missing '@Configuration' on top of '@EnableWebFluxSecurity' – SeaBiscuit Feb 19 '23 at 22:16
  • This works out of the box: https://docs.spring.io/spring-security/reference/5.8/migration/reactive.html#reactive-csrf-breach-opt-out – Ubaid ur Rehman May 03 '23 at 03:00

0 Answers0