October 22, 2024
Chicago 12, Melborne City, USA
java

Spring Security CSRF protection customization on Reactive WebFlux applications


I’m working on a microservices architecture that combines servlet and reactive Spring Boot applications; these are deployed on a K8S cluster, and each microservice exposes the Spring Actuator endpoints for health monitoring and logging management: in fact, we use the /actuator/loggers endpoints in POST to set specific levels at runtime. This may happen by curl calls from terminal, or from management applications like Spring Boot Admin.

I published two examples of these microservices at https://github.com/polifr/csrf-servlet and https://github.com/polifr/csrf-reactive, complete with junit test classes and three different CSRF configurations (disabled, enabled, customized with specific exclusions); I will refer to the sources of these projects to explain further the situation.

The logging configuration endpoint falls under the management of the CSRF policy because is called with a POST. In the case of servlet, an exclusion can be set using the ignoringRequestMatchers method, like this (CsrfIgnoringSecurityConfiguration of the csrf-servlet project):

log.debug("Csrf is enabled");
http.csrf(
    csrf ->
        csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            .ignoringRequestMatchers(EndpointRequest.to(LoggersEndpoint.class)));

In this case, it is done a decoration to the CSRF policy that has been set by the context.

Instead, for the reactive stack, there is no equivalent method; I tried the solution given for How to add CSRF disable for specific URL in Spring Web Flux Basic Authentication (Reactive Programming), but it does not work: in fact, it would CSRF-block all the other endpoint, also the GET ones.
At the moment, the only solution I have found is this (CsrfIgnoringSecurityConfiguration of the csrf-reactive project):

log.debug("Csrf is enabled");
http.csrf(
    csrf ->
        csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
            .requireCsrfProtectionMatcher(
                new AndServerWebExchangeMatcher(
                    CsrfWebFilter.DEFAULT_CSRF_MATCHER,
                    new NegatedServerWebExchangeMatcher(
                        EndpointRequest.to(LoggersEndpoint.class)))));

But in this case, I am overwriting the context-managed CSRF policies, that may include specific exclusions, e.g. authentication. See for example Spring Security ServerHttpSecure:

private void registerDefaultCsrfOverride(ServerHttpSecurity http) {
    if (http.csrf != null && !http.csrf.specifiedRequireCsrfProtectionMatcher) {
        AndServerWebExchangeMatcher matcher = new AndServerWebExchangeMatcher(
                CsrfWebFilter.DEFAULT_CSRF_MATCHER,
                new NegatedServerWebExchangeMatcher(this.authenticationConverterServerWebExchangeMatcher));
        http.csrf().requireCsrfProtectionMatcher(matcher);
    }
}

Apart from trying to ask the Spring Community to implement also for the reactive stack an ignoringRequestMatchers method, does anybody have some suggestions about how to implement this kind of CSRF customization in a cleaner way?



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video