JWT Token and CSRF

Viewed 10538

I am still not clear in regards to the JWT and CSRF working together. I understand the fundamentals for the JWT (what it is and how it works). And I also understand the CSRF when used with sessions. Similarly I understand that there are risks involved with storing the JWT in localStorage and that's why you need the csrf token. So my question is, how do I use them both. For simplicity say that I have a login page.

1) I have the user signing in and once the email and password are consumed if the user is authenticated the server will send a CSRF and will store a httpOnly cookie with the JWT (how do I set the cookie using PHP). What I understood is that you can use header('Set-Cookie: X-Auth-Token=token_value; Secure; HttpOnly;');please confirm if thats the way to do it.

2) Once I have set the cookie with the JWT. How I am sending the CSRF token with subsequent requests> From what I understood, you set them in the headers. So if I am making an Ajax request I will put them in the headers.

3) Once the request is made and the CSRF token is sent along with the request. How is the validation made. What am I comparing?

Last, is this safe to implement!

I would highly appreciate if you could include as much details as possible.

2 Answers

One approach that I've seen and used myself is to include the CSRF token inside the JWT as a claim. So when the user sends username and password, you can do the following:

  1. If username and password are correct, proceed with the following listing.
  2. Create a new JWT and include a generated CSRF token in the payload as a claim, then sign the JWT.
  3. Respond to client's authentication request by setting an HTTPOnly cookie which contains the JWT. This ensures that only the browser (not the client side app and possibly malicious scripts) has access to the JWT. It's also a good idea to set the cookie to secure. This prevents the browser from sending the cookie if an unsecured communication channel is used (i.e. not https).
  4. When setting the JWT cookie, you should also set an HTTP header which will also contain your generated CSRF token. Note that now you will have the CSRF token in two places—inside the JWT cookie and in an HTTP header.
  5. In your client app, store the CSRF token from the header into localstorage.
  6. For each request, take the CSRF token from localstorage and include it as a request header (the cookie containing the JWT is passed along automatically by the browser).
  7. The server should read the JWT from the cookie, validate its signature and read the CSRF token from the JWT's payload. Then it should compare it against the CSRF token that's in the request header. If they match, the server can continue processing the request.

I suggest you to watch this talk about JWTs. It goes into more details about the same approach (also with nice diagrams). Feel free to watch the entire talk or if you're interested specifically in CSRF, start from 36:29.

The following is a slide (from the presentation linked above) that demonstrates how JWT and CSRF tokens could be used together. I annotated it with red numbers which correspond to the listing above. Sequence diagram of JWT and CSRF working together

The common paradigm to defend against CSRF it to generate a token for each "form", and validate that the token that was set for the specific form is correct.

That way, attacker can't guess the token therefore can't make an external form that sends to your server.

Usually, the method to set that token is via Cookie and the client app will attach it to some custom header, that will give you an additional protection, then, the server should compare between the cookie value and the header value.

It is important that the token will be valid only for one session, otherwise, an attacker can reuse the same token that he got in the attack vector.

JWT, is a method to authenticate the user to the system not to validate that the request was valid.

I will try to explain by example, assume you are didn't implemented any protection against CSRF, but you do have a mechanism to authenticate your users (with usage of JWT), so the user logged in with the correct user & pass, your server will send a JWT, the client will save it to localStorage / memory. Now, the attacker can craft a form on his site that will point to your server, assume that he knows the users JWT token (he got it with other methods like MITM), all he needs to do is to trick the user into going his page with the form, and the form will be sent to you with any problem, your server will accept the request and the attack will succeed.

If you implement any CSRF mechanism, the attacker at the example will not be able to guess the current token, therefore your server will ignore his request.

Related