'CSRF token is generated again, doesn't use the one it already has

We have a Java based application with the front-end in Vuejs.

The application has a CsrfRequestMatcher that bypasses GET reqests.

The problem we're facing is with SSO. It is our custom Login/SSO we are not using any third party APIs for it.

This is the use case that breaks our application:

  1. The user successfully SSOs in.
  2. The user can move around the application doing POST requests.
  3. The user doesn't logout, but closes the tab.
  4. The user SSOs in again.
  5. Lands fine in the application, but as soon as they do a POST request, the application says invalid CSRF token and throws them on the login page.

All this takes place in the org.springframework.security.web.csrf.CsrfFilter class.

Here's the code snippet:

CsrfToken csrfToken = this.tokenRepository.loadToken(request);
final boolean missingToken = csrfToken == null;
if (missingToken) {
    csrfToken = this.tokenRepository.generateToken(request);
    this.tokenRepository.saveToken(csrfToken, request, response);
}
request.setAttribute(CsrfToken.class.getName(), csrfToken);
request.setAttribute(csrfToken.getParameterName(), csrfToken);

if (!this.requireCsrfProtectionMatcher.matches(request)) {
    filterChain.doFilter(request, response);
    return;
}

String actualToken = request.getHeader(csrfToken.getHeaderName());
if (actualToken == null) {
    actualToken = request.getParameter(csrfToken.getParameterName());
}
if (!csrfToken.getToken().equals(actualToken)) {
    if (this.logger.isDebugEnabled()) {
        this.logger.debug("Invalid CSRF token found for "
                + UrlUtils.buildFullRequestUrl(request));
    }
    if (missingToken) {
        this.accessDeniedHandler.handle(request, response,
                new MissingCsrfTokenException(actualToken));
    }
    else {
        this.accessDeniedHandler.handle(request, response,
                new InvalidCsrfTokenException(csrfToken, actualToken));
    }
    return;
}

Upon debugging I see that the code in CsrfFilter still has the csrfToken it generated the last time on the first call / SSO.

Then the user is redirected to a different page (Still a GET request), and the CsrfFilter is called again. This time CsrfToken csrfToken = this.tokenRepository.loadToken(request); is null. This reads it from the session so don't understand why is that null?

So it generates a new CsrfToken, and the UI has an old CsrfToken obviously, so the next POST call generates the Invalid CSRF token error, because of token mismatch.

We are using an older version of Spring (1.4), so please take this in to account when you answer.

Any help is appreciated to resolve this CSRF token issue.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source