question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

CsrfWebFilter not generating the CSRF token with Webflux

See original GitHub issue

Summary

I have a Spring Webflux application secured by Spring Security with CSRF protection enabled by default. In this application, I can’t get the CSRF token to be saved in the Websession nor added in the model.

Actual Behavior

After some investigations, I noticed that the problem comes from Spring Security’s CsrfWebFilter.class, in which there is the following method:

private Mono<Void> continueFilterChain(ServerWebExchange exchange, WebFilterChain chain) {
        return Mono.defer(() -> {
            Mono<CsrfToken> csrfToken = this.csrfToken(exchange);
            exchange.getAttributes().put(CsrfToken.class.getName(), csrfToken);
            return chain.filter(exchange);
        });
    }

In this method, the CsrfToken Mono is never subscribed, which prevents the token to be generated and added in the Websession.

Moreover, when my page is rendered, the _csrf parameter is null in the view model.

Expected Behavior

The CsrfToken Mono should be subscribed so that the WebSessionServerCsrfTokenRepository could generate and save the token in the Websession. The _csrf parameter should be accessible from the view model (maybe this one is an issue with Thymeleaf).

Workaround

As a workaround, I rewrite the CsrfWebFilter in my application and just override the above method this way:

private Mono<Void> continueFilterChain(ServerWebExchange exchange, WebFilterChain chain) {
        return Mono.defer(() -> {
            return this.csrfToken(exchange)
                    .doOnNext(csrfToken -> exchange.getAttributes().put(CsrfToken.class.getName(), csrfToken))
                    .then(chain.filter(exchange));
        });
    }

Then, to be able to retrieve the _csrf parameter in the model, I add this method in an abstract controller:

@ModelAttribute("_csrf")
    public CsrfToken csrfToken(final ServerWebExchange exchange) {

        return exchange.getAttribute(CsrfToken.class.getName());
    }

Is it a valid workaround?

Configuration

Here is my Security configuration class:

@EnableWebFluxSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityWebFilterChain springWebFilterChain(final ServerHttpSecurity http) {

        http.authorizeExchange()
                .pathMatchers("/**").permitAll()
                .and()
                .oauth2Login()
                .and()
                .oauth2Client();

        return http.build();
    }

    @Bean
    public ServerOAuth2AuthorizedClientRepository authorizedClientRepository(
            final ReactiveOAuth2AuthorizedClientService authorizedClientService) {

        return new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
    }
}

Version

My application runs on Netty with Spring Boot 2.1.0.RELEASE, Spring Security 5.1.1.RELEASE, and Thymeleaf 3.0.10.RELEASE.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:18 (3 by maintainers)

github_iconTop GitHub Comments

5reactions
dilliuscommented, Apr 7, 2019

Is there a way to solve this problem if you are using functional framework in Spring 5? The ControllerAdvice doesn’t seem to have any effect if you aren’t actually defining Controllers.

4reactions
broth-eucommented, Jun 30, 2020

In case one does not have a controller, the simplest workaround is to implement a custom WebFilter which places the Mono<CsrfToken> inside of the filter chain like so:

public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
	Mono<CsrfToken> token = (Mono<CsrfToken>) exchange.getAttributes().get(CsrfToken.class.getName());
	if (token != null) {
		return token.flatMap(t -> chain.filter(exchange));
	}
	return chain.filter(exchange);
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

CSRF token not generated with Webflux - Stack Overflow
This worked for us because one of the places CsrfWebFilter expects to find the token is in the request header X-XSRF-TOKEN .
Read more >
Cross Site Request Forgery (CSRF) for WebFlux Environments
Spring Security's CsrfWebFilter exposes a Mono<CsrfToken> as a ServerWebExchange attribute named org.springframework.security.web.server.csrf.
Read more >
[Solved]-CSRF token not generated with Webflux-Springboot
This worked for us because one of the places CsrfWebFilter expects to find the token is in the request header X-XSRF-TOKEN . jndietz...
Read more >
A Guide to CSRF Protection in Spring Security - Baeldung
Learn how CSRF attacks work on a practical Spring application, and then how to enable ... Spring adds a CSRF token to each...
Read more >
spring-projects/spring-security - Gitter
Seems like you are talking about authorization and not authentication here. ... there are lots of different libraries out there for creating tokens....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found