Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should I put a CSRF token in a JWT token?

I want to bring a doubt about JWT tokens and CSRF from the Stormpath post that explain the advantages and disadvantages of storing the JWT either in localStorage or cookies.

[...] if you are reading values out of a cookie using JS, that means you can't set the Httponly flag on the cookie, so now any JS on your site can read it, thus making it the exact same security-level as storing something in localStorage.

I'm trying to understand why they recommend adding the xsrfToken to the JWT. Doesn't storing your JWT in the cookie and then extracting it out and placing the JWT in the HTTP header and authenticating the request based on the HTTP header accomplish the same thing as Angular's X-XSRF-TOKEN? No other domain could make requests on a user's behalf if you authenticate based on the JWT in the header, since other domains cannot extract the JWT from the cookie. I don't understand the purpose of the xsrfToken in the JWT - perhaps its just an additional layer of defense - meaning that attackers would have to have a compromised script on your site and CSRF a user at the time. So they'd have to hit you in both ways to be able to pull of an attack.

The post is linked in this answer where says:

The last thing is to ensure that you have CSRF protection on every HTTP request to ensure that external domains initiating requests to your site cannot function.

[...] Then, on every request into your server, ensure that your own JavaScript code reads the cookie value and sets this in a custom header, e.g. X-CSRF-Token and verify that value on every request in the server. External domain clients cannot set custom headers for requests to your domain unless the external client gets authorization via an HTTP Options request, so any attempt at a CSRF attack (e.g. in an IFrame, whatever) will fail for them.

Even if they could set custom headers, they couldn't access the cookie where the JWT token is stored because only JavaScript that runs on the same domain can read the cookie.

The only way they could is via XSS, but having an xsrfToken in the JWT is compromised too if exists XSS vulnerabilities because a malicious script running in the trusted client domain could access the JWT in the cookie and include a header in the request with the xsrfToken.

So the equation should be:

  • TLS + JWT stored in secure cookie + JWT in request header + No XSS vulnerabilities.

If the client and server are running in different domains, the server should send the JWT and the client should create the cookie with the JWT. I think that the equation is still valid for this situation.

UPDATE: MvdD agree with me:

As the browser does not automatically add the header to your request, it is not vulnerable to a CSRF attack

like image 496
gabrielgiussi Avatar asked Jan 26 '16 12:01

gabrielgiussi


2 Answers

I am the author of the Stormpath Blog Post. Storing XSRF token in the JWT isn't about that it is in the JWT, it is about that it is in a cookie. The cookie should be httpOnly, so you can not read it from Javascript.

Now, I think the point that caused a little confusion is where I talk about angular. Angular sets it's only XSRF cookie as well (which is not httpOnly) to put it into the header at request time (which can only be done by javascript on same domain). These are not the same cookie.

If you think about implementing XSRF support in your application, this has been done with storing server side state and the point of storing the XSRF. Storing it in the httpOnly cookie is about being stateless with XSRF. Here, you would validate the JWT signature, get the XSRF out of the claims, and compare it to the header.

The answer to your question is so that you do not need to store state on your server.

like image 184
Tom Abbott Avatar answered Oct 11 '22 10:10

Tom Abbott


My understanding was this:

  • Store JWT is an HTTPonly cookie.
  • In that JWT, store a hashed version of an XSRF token.
  • Send the client the XSRF token when they sign in so they can store it in local storage
  • Later when the client sends requests, the JWT is automatically sent with each request via cookies and then you also send the XSRF token via a header or query variable and on the server side, re-hash to compare to what's in the JWT on the server

Your JWT is protected from being stolen in a XSS and you're protected from XSRF. XSS could still execute on your browser but could only do damage for that session in the browser. Ultimately, You couldn't stop someone from writing a really detailed script that just ran on your browser, so conventional safeties to protect from XSS are still needed by the web developer.

like image 24
Chiedo Avatar answered Oct 11 '22 09:10

Chiedo