venkatReddi
venkatReddi

Reputation: 163

How does the spring internally validate the csrf token with _csrf parameter or X-CSRF-TOKEN header?

I am using spring and enabled csrf with HttpSessionCsrfTokenRepository, I clearly know if the client is sending the csrf token either as _csrf parameter or X-CSRF-TOKEN header for the request spring picks up the token and validates with the token which was generated using generateToken(HttpServletRequest request) But my question is how does spring does this internally. My reason for this question being:

1.I have a Rest POST call which takes credentials and validates the identity of the user. But Since I want to add a csrf token to the rest call as a layer of security I wanted to add it in the post body to prevent csrf token leak.

So if I know how spring security filters these tokens internally it would be helpful. I revised the spring documentation but it is mostly how we can use CSRF token in a form with hidden field or meta tags and Ajax call with a header.

And I also would like to hear any comments on my design if it is good to have the token in body( I am convinced because it would not be a simple url parameter to leak the token ) or should I have it in the header. I just dont want to lean to use header just because its simple. Looking for the best solution.

Please shed some light.

Upvotes: 3

Views: 7651

Answers (2)

Harsh Shiyani
Harsh Shiyani

Reputation: 109

Note: This info is for Spring Security 6, but it's probably the same for older versions too.

The request type should be POST/PUT/DELETE to debug the flow yourself. (Not GET what I want to say)

Now, let's jump into the flow.

  • First, we have a CsrfTokenRepository interface implemented by two classes: CookieCsrfTokenRepository & HttpSessionCsrfTokenRepository
  • Considering that we are using cookie-based CSRF token. For that, CookieCsrfTokenRepository will be used.
  • Internally, the method loadToken(HttpServletRequest request) will be called to extract the token from the cookie received from the request. (loadToken method is in RepositoryDeferredCsrfToken class)
  • If a CSRF token is found from the cookie, an object of DefaultCsrfToken will be created. (new DefaultCsrfToken(this.headerName, this.parameterName, token))
  • Now, the actual validation part resides in the CsrfFilter class.
  • The requestHandler.resolveCsrfTokenValue(request, csrfToken) method extracts the CSRF token from the header/param. (The method looks like this below)
@Override
default String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
    Assert.notNull(request, "request cannot be null");
    Assert.notNull(csrfToken, "csrfToken cannot be null");
    String actualToken = request.getHeader(csrfToken.getHeaderName());
    if (actualToken == null) {
        actualToken = request.getParameter(csrfToken.getParameterName());
    }
    return actualToken;
}
  • So, one CSRF token extracted from the cookie and another from the header/param are compared, and a decision will be made accordingly.
  • If they are equal, then woohoo :) else, a 403 forbidden status is returned as usual :(

Upvotes: 0

Jayesh
Jayesh

Reputation: 999

There're multiple implementations for CsrfTokenRepository in spring if you want to look into into it. for eg:

https://github.com/rwinch/spring-security/blob/master/web/src/main/java/org/springframework/security/web/csrf/HttpSessionCsrfTokenRepository.java

https://github.com/rwinch/spring-security/blob/master/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java

https://github.com/rwinch/spring-security/tree/master/web/src/main/java/org/springframework/security/web/csrf

https://docs.spring.io/spring-security/site/docs/4.2.7.RELEASE/apidocs/org/springframework/security/web/csrf/CookieCsrfTokenRepository.html

https://docs.spring.io/spring-security/site/docs/4.2.7.RELEASE/apidocs/org/springframework/security/web/csrf/CookieCsrfTokenRepository.html

IMO its good (safer - may be?) to keep Tokens on the header because of few reasons that i can think of..

  1. You cannot set token on a body for your GET request. You want to be consistent of all your endpoints (you may not need it today but things change really fast)

  2. Tomorrow if you want to change your Auth model, you dont want to to change your request body. when request body changes you break the contract with clients

  3. If you change your auth model to a authorization server, you can add proxy server (like ngnix?) before your service and lets call it auth-proxy. You can leave all security related things to this auth-proxy and it will inspect the header and do the validations for you. You don't want the proxy to look into your request body and you can focus on your business implementation

  4. Request body is completely related to your business so you can focus on it vs dealing with security related things in your body.
  5. Everytime you create a new Request for a new endpoint you don't want to keep adding tokens in all the requests

It's just my opinion based on my experience.

Upvotes: 4

Related Questions