Spring Single Page Application: CSRF token changes silently after login, logout, etc.

As I know, in a Spring + JavaScript single page application, we need to send a CSRF token to the client somehow.

The recommended way would be to have CsrfHeaderFilter

, as described in this Spring guide . Following this approach, when the application starts, it will send a GET request to the server and retrieve the token.

But I see that on certain events like login or logout, Spring Security changes the token. CsrfHeaderFilter

comes in early and therefore cannot detect the change. Hence, I need to send another GET request after such events.

I tried to peek at the Spring security code to see if there would be a way to send the modified token along with these login or logout requests, so that another GET request would be saved. But couldn't find a way.

Liked to find out if a bogus GET request is sending after login, logout, etc., as I am currently doing, looks like a good solution. Or maybe there is a better way?

If there is currently no way to avoid this redundant GET request, I was wondering if this would be the ticket for Spring Security to come up with something after which it would be possible.

+3


source to share


1 answer


A similar situation happened with CookieCsrfTokenRepository.

The application I was working in has a custom implementation of a login using a REST service. The service has a call to httpServletRequest.logout () internally, which (as I found out) resulted in the XSRF-TOKEN cookies being cleared in response:

Set-Cookie:XSRF-TOKEN=; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ibdrs; Secure

      

Without the new XSRF-TOKEN value in the answer, I had two options:



  • Make a dummy request for a new XSRF-TOKEN right after login (as OP suggested)

  • Update XSRF-TOKEN in the same login answer as for clearing the cookie.

It turned out that the second option can be achieved:

  • Created my own CustomCookieCsrfTokenRepository as a copy of CookieCsrfTokenRepository (source code here ). If it weren't definitive, it would be sufficient to expand it instead of copying it.

  • Changed all occurrences of CookieCsrfTokenRepository to CustomCookieCsrfTokenRepository inside copy

  • Replaced the saveToken method with a newer version that never clears the cookie:

    @Override
    public void saveToken(CsrfToken token, HttpServletRequest request,
                      HttpServletResponse response) {
        if (token == null) {
            token = generateToken(request);
        }
        String tokenValue = token.getToken();
        Cookie cookie = new Cookie(this.cookieName, tokenValue);
        cookie.setSecure(request.isSecure());
        if (this.cookiePath != null && !this.cookiePath.isEmpty()) {
            cookie.setPath(this.cookiePath);
        } else {
            cookie.setPath(this.getRequestContext(request));
        }
        cookie.setMaxAge(-1);
        if (cookieHttpOnly && setHttpOnlyMethod != null) {
            ReflectionUtils.invokeMethod(setHttpOnlyMethod, cookie, Boolean.TRUE);
        }
        response.addCookie(cookie);
    }
    
          

  • Configure HttpSecurity to use the new class:

    .csrf()
        .csrfTokenRepository(CustomCookieCsrfTokenRepository.withHttpOnlyFalse())
        .and()
    
          

+1


source







All Articles