Grego
Grego

Reputation: 327

Webflux disable CSRF on specific URLs

The idea is to replicate http://blog.netgloo.com/2014/09/28/spring-boot-enable-the-csrf-check-selectively-only-for-some-requests/ in webflux.

This is where I got so far:

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {

    @Bean
    SecurityWebFilterChain springSecurityFilterChain(final ServerHttpSecurity http) {
        http
           .csrf().requireCsrfProtectionMatcher(
                  new ServerWebExchangeMatcher() {

                    @Override
                    public Mono<MatchResult> matches(ServerWebExchange serverWebExchange) {
                    // here check if the url should have csrf or not and then return MatchResult.match() or notMatch(), however I find that if I return match then I get 'Invalid CSRF Token' error.
                    //    return MatchResult.match();
                    //    return MatchResult.notMatch();
                    }
                }
                ).and()
                .anyExchange().authenticated()
                .and()
                .httpBasic()
                .and()
                .formLogin().loginPage("/login")
                .and().logout()

        return http.build();
    }
}

Upvotes: 3

Views: 6501

Answers (4)

Jordan Dodd
Jordan Dodd

Reputation: 1

I think you are just removing all security protocol from these post/put endpoints (likely change the data). Better off having CSRF disabled and still benefiting from Spring authentication chain. Just hitting these with a permit all removes any need for a user to even be logged int. Not a good answer.

Upvotes: 0

Ubaid ur Rehman
Ubaid ur Rehman

Reputation: 148

I am too late but after a lot of research, I got a nice solution.

Let assume you want to disable CSRF check on a specific URL. In my case, I want to disable CSRF check on URLs matching this pattern /token/**.

So, first, you need to create a NegatedServerWebExchangeMatcher instance in which you will add all URLs pattern for which you want to disable CSRF check. In my case, I will create a method that returns NegatedServerWebExchangeMatcher only for the /token/** pattern. So, here is my method.

    public NegatedServerWebExchangeMatcher getURLsForDisabledCSRF() {
        return new NegatedServerWebExchangeMatcher(exchange -> ServerWebExchangeMatchers.pathMatchers(ALLOWED_PATHS).matches(exchange));
    }

Now delegate getURLsForDisabledCSRF() in your requireCsrfProtectionMatcher method like below:

        http
                .csrf().requireCsrfProtectionMatcher(getURLsForDisabledCSRF())

Here is my Security Config Class for my Spring Cloud API Gateway which is actually using web flux.

package com.ubaid.ms.gatewayserver.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.util.matcher.NegatedServerWebExchangeMatcher;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;

/**
 * <pre>
 * 1. Configure
 *      a. Authorize only authenticated requests except {@link SecurityConfig#ALLOWED_PATHS}
 *      b. OAuth 2.0 Resource Server support
 * 2. Disable CSRF on {@link SecurityConfig#ALLOWED_PATHS}
 * </pre>
 *
 * @author ubaid
 */
@Configuration
@EnableWebFluxSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class SecurityConfig {

    private final static String[] ALLOWED_PATHS = {"/token/**"};

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {

        http
                .csrf().requireCsrfProtectionMatcher(getURLsForDisabledCSRF())
                .and()
                .authorizeExchange()
                .pathMatchers(ALLOWED_PATHS).permitAll()
                .pathMatchers(HttpMethod.OPTIONS).permitAll()
                .anyExchange()
                .authenticated()
                .and()
                .oauth2ResourceServer()
                .jwt();

        return http.build();
    }

    public NegatedServerWebExchangeMatcher getURLsForDisabledCSRF() {
        return new NegatedServerWebExchangeMatcher(exchange -> ServerWebExchangeMatchers.pathMatchers(ALLOWED_PATHS).matches(exchange));
    }
}

Note: Spring Cloud Version: 2020.0.2

Upvotes: 4

hatanooh
hatanooh

Reputation: 4287

config allowedOrigins:

@Bean
public WebFluxConfigurer corsConfigurer() {
    return new WebFluxConfigurerComposite() {

        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry
                .addMapping("/**")
                .allowedOrigins("/goodss")
                .allowedMethods("*");
        }
    };
}

Upvotes: -4

McGin
McGin

Reputation: 1401

This should do it

    @Bean
    SecurityWebFilterChain springSecurityFilterChain(final ServerHttpSecurity http) {
        http
           .csrf().requireCsrfProtectionMatcher(
                  new ServerWebExchangeMatcher() {

                    @Override
                    public Mono<MatchResult> matches(ServerWebExchange serverWebExchange) {
                        ServerWebExchangeMatchers.pathMatchers("/urls-with-csrf-check/**").matches(serverWebExchange)
                    }
                }
                ).and()
                .anyExchange().authenticated()
                .and()
                .httpBasic()
                .and()
                .formLogin().loginPage("/login")
                .and().logout()

        return http.build();
    }

Upvotes: 4

Related Questions