slon slon
slon slon

Reputation: 203

Why I recieve invalid csrf token?

I have a project with spring-cloud-security. It's a auth server for oauth authorization. It's worked fine in the past.

I add spring profile for ssl support with cofiguration:

security:
  require-ssl: true
server:
  ssl:
    key-store: dev.p12
    key-store-password: devpass
    keyStoreType: PKCS12
    keyAlias: calc

With this profile, authentication works fine, but when I disable it and go to login via http, authentication breaks down.

o.s.security.web.csrf.CsrfFilter         : Invalid CSRF token found for http://localhost:8090/login

How can I fix it?

Upvotes: 19

Views: 60706

Answers (2)

Satrajit A
Satrajit A

Reputation: 310

If I understand correctly, the issue is that CSRF protection works when ssl is enabled and the application is accessed using https but it breaks when ssl is disabled and the application is accessed using http.

Root Cause:

Once CSRF is enabled (by default using @EnableWebSecurity) or by using a config similar to below

http.csrf()
    .and()...

OR

http.csrf(Customizer.withDefaults())

CSRF protection will be applied to both http and https requests.

The CSRF configuration uses a token repository, by default it is HttpSessionCsrfTokenRepository, under the hood. The token repository generates a new token for each request (which matches the CSRF protection rule) and stores it. When a request is submitted, the token passed in the request, as _csrf parameter in the request body, is matched against the token saved in the store.

Session management relies on the cookie JSESSIONID. If the server.servlet.session.cookie.secure is set to true, then the cookie is only sent for https requests. Since the CSRF token is saved in a session store, and the JESSIONID cookie is not sent for http requests, retrieving the csrf token from the session store does not work and hence it is unable to perform the match.

Solution 1:

A workaround could be using something like below

http.csrf(csrfConfigurer -> csrfConfigurer.csrfTokenRepository(new CookieCsrfTokenRepository())

OR

@Bean
public CsrfTokenRepository csrfTokenRepository() {
    return new CookieCsrfTokenRepository();
}

What is does is that instead of saving the generated CSRF token in a session store, it stores it in a cookie. So the _csrf parameter value is matched against the XSRF-TOKEN cookie value. By default this cookie does not have the Secure attribute set so it works for http requests.

Solution 2

Solution 1 will fix the CSRF issue but the session cookie is needed to store the securityContext between requests. In that case you can set server.servlet.session.cookie=false

P.S. The answer is based on Spring Framework 6.x.

Upvotes: 2

Misantorp
Misantorp

Reputation: 2821

Your server has CSRF enabled. The @EnableWebSecurity annotation will enable CSRF by default as stated in the documentation.

CSRF protection is enabled by default with Java configuration.

There are two ways to "fix" this, either disable CSRF or submit the CSRF-token when doing PATCH, POST, PUT, and DELETE actions.

To disable CSRF do it in the Spring Security configuration

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
  }
}

To submit the CSRF-token you must include it in the request to the server (in this example a JSP with sending a POST request)

<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}" method="post">
  <input type="submit" value="Log out" />
  <input type="hidden" name="${_csrf.parameterName}"
    value="${_csrf.token}"/>
</form>

All examples taken from the Spring Cross Site Request Forgery (CSRF) documentation

Please consider the recommendation from Spring when considering whether to disable CSRF

[...] use CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.

Upvotes: 29

Related Questions