3

I am working through some architecture issues in my head related to JWT authentication security and I'm trying to figure out the following:

  1. How does JWT securely pass a secret between server and client?

  2. Take a look at the below excerpt from from https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/ ....................

CSRF can be prevented by using synchronized token patterns. This sounds complicated, but all modern web frameworks have support for this.

For example, AngularJS has a solution to validate that the cookie is accessible by only your domain. Straight from AngularJS docs:

'When performing XHR requests, the $http service reads a token from a cookie (by default, XSRF-TOKEN) and sets it as an HTTP header (X-XSRF-TOKEN). Since only JavaScript that runs on your domain can read the cookie, your server can be assured that the XHR came from JavaScript running on your domain. You can make this CSRF protection stateless by including a xsrfToken JWT claim:'

{ "iss": "http://galaxies.com", "exp": 1300819380, "scopes": ["explorer", "solar-harvester", "seller"], "sub": "tom@andromeda.com", "xsrfToken": "d9b9714c-7ac0-42e0-8696-2dae95dbc33e" }

  1. How does the client create and send a valid request including the xsrfToken claim unless it can first sign the JWT after including the claim? (This xsrfToken after all is what's supposed to keep EvilBob from forging a request right?)

More details regarding my current understanding of the JWT XSRF process can be found here http://spring.io/blog/2013/08/21/spring-security-3-2-0-rc1-highlights-csrf-protection/.

PLanger
  • 33
  • 5

2 Answers2

2
  1. I can explain how Stormpath does it, there are some other ways as well. Stormpath includes a 'kid' (key id) field in the JWT header, which is the identifier for the API Key ID / Secret pair. The JWT was signed with the Secret, and the ID is stored in key id field. When Stormpath validates the token, it can retrieve the secret. This works across servers and services but is never passed to the client. Using the client to glue separate services together with the secret is extremely insecure.

  2. The client SHOULD NOT generate the JWT, this needs to be done on the server. The server knows the XSRF token and can sign it in the JWT and put it in the cookie.

Hope this information helps!

Tom Abbott
  • 481
  • 3
  • 5
  • Okay, there were some key things I was misunderstanding about how the JWT process works. 1) The server is the only one who knows the Secret. The same Secret is used for signing and verifying all users' request. 2) Only the real client has access to the cookie storing the auth-token and xsrf-token. Attackers can submit an attack request, but the attack request won't have the xsrf-token as an HTTP header. Thus making the request invalid. 3) Once the request reaches the server, server will check to see if header contains the xsrf-token, and If so compare it to the xsrf-token in the JWT payload. – PLanger Dec 03 '15 at 21:26
  • I second Davorins confusion [here](https://disqus.com/home/discussion/stormpath/where_to_store_your_jwts_cookies_vs_html5_web_storage_stormpath_user_management_api/oldest/) – Rhubarb Apr 29 '16 at 11:32
  • 1
    ...So i take it that 1. xsrftoken is created at the same time the jwt is created and signed. 2. it comes downstream in a NON-httponly cookie. 3. the JWT IS in httpONLY cookie to reduce XSS. 4. ajax request includes xsrfToken (which only same origin JS knows) and browser includes jwt (which NO JS knows) and the server compares to validate the request. Is that the plan?.... All good, but ... Can't XSS get the xsrftoken cookie just as easily as it could have got the JWT from localstorage if I had used that instead? – Rhubarb Apr 29 '16 at 11:38
1

The article appears to call this the "synchronized token pattern", however the solution described better fits with the Double Submit Cookies method rather than the Synchronizer Token Pattern.

Double submit cookies involves sending the cookie value in a header or body as well as sending it with the browser cookies that are automatically sent. If you are not supporting CORS, then setting a token in a header is secure anyway, as is with any custom header value (e.g. X-Requested-With). This is because a custom header cannot be sent cross-domain in the first place, so verifying that it has transported from the client verifies that it is not from another domain already. As a defence in depth strategy, you can set it to a random value, as explained by this answer.

The random value doesn't need to come from the server, nor be signed. It just needs to be generated by a CSPRNG. If generated client-side, window.crypto should be used for this. All the server does is check that the header and cookie values match.

A third party domain cannot forge a request because even though the cookie value will be sent by the browser automatically from the victim's machine, the attacker cannot include the value in the header or the request body.

With the Synchronizer Token Pattern the CSRF token is generated server-side and stored against the session. This value has to be sent from each form submission and is verified server-side that it matches the stored token.

Community
  • 1
  • 1
SilverlightFox
  • 32,436
  • 11
  • 76
  • 145
  • Wow, thank you very much @SilverlightFox. This was very thorough and very helpful including multiple alternatives. Thanks much for the feedback. – PLanger Dec 09 '15 at 04:30