16

I'm in need of a CSRF token, for a certain application that submits a form with POST. Ideally, I'd like to not make a DB call for each submission, to avoid storage and DB traffic & latency. To this end OWASP's "CSRF Prevention Cheat Sheet" says,

Overview

The Encrypted Token Pattern leverages an encryption, rather than comparison, method of Token-validation. After successful authentication, the server generates a unique Token comprised of the user's ID, a timestamp value and a nonce, using a unique key available only on the server. This Token is returned to the client and embedded in a hidden field. […] Non-AJAX form-based requests will implicitly persist the Token in its hidden field. On receipt of this request, the server reads and decrypts the Token value with the same key used to create the Token. […]

Validation

On successful Token-decryption, the server has access to parsed values, ideally in the form of claims.

The first line of "Validation" reads, to me, like the very defintion of a JWT. I'm not seeing why the information in token needs to be encrypted, either: it would seem it merely needs to be authenticated that it came from the server (as opposed to an attacker attempting forging a CSRF token.)

Is there any particular reason to encrypt CSRF tokens? If not, does a JWT suffice?

Also, the above token pattern includes a nonce. What is the point of the nonce? (The whole point of this pattern is to not store any state server-side. If I'm not storing state, how can I use the nonce during validation in any material manner?)

My main reason for pursuing JWTs here is that there's decent library support, I'll probably want them for auth sooner or later, and it mostly keeps me away from implementing crypto stuff.

My understanding of JWTs is that if I had JWTs for full user authentication, I could store those in localStorage, and simply add those to a field with JS prior to form submission. Unfortunately, the app uses cookie-based auth, and I'm not able to change that aspect right now.

  • It's helpful to define your acronyms. I think CSRF is readily known in the security community, but JWT looks relatively new. Keep in mind this is a cross-discipline field. – Steve Sether Feb 25 '16 at 19:23
  • See this comment on the OWASP wiki that stemmed from another question about the encrypted token pattern. It seems to me that that section is sloppily written. – Neil Smithline Feb 25 '16 at 19:24
12

There is no need to encrypt the token or to include the nonce. The key properties of a CSRF token are that it is not predictable by an attacker, and, unlike cookies, that it is not added to every request by the browser. A cryptographically secure JWT stored in a hidden field meets both of these properties.

Note that you need to use JWT's that have user-unique data in them. Having an empty or generic JWT that isn't specific to the user will not provide you with security.

  • 3
    TL;DR: yes you can use a user unique JWT as your CSRF token/validation as long as it is not stored in a Cookie. – Scott Jungwirth May 11 '16 at 17:19
  • Q pls @ScottJungwirth what you mean by that "you can use a user unique JWT as your CSRF" ? – BG Bruno Dec 23 '18 at 16:54
19

TL;DR

A JWT, if used without Cookies, negates the need for a CSRF token - BUT! by storing JWT in session/localStorage, your expose your JWT and user's identity if your site has an XSS vulnerability (fairly common). It is better to add a csrfToken key to the JWT and store the JWT in a cookie with secure and http-only attributes set.

Read this article with a good description for more info https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage

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" }

So you will need to store the csrfToken in local/sessionStorage as well as inside the JWT (which is stored in a http-only and secure cookie). Then for csrf protection, verify that the csrf token in the JWT matches the submitted csrf-token header.

  • My read of this is that JWT with CSP (content-security-policy) would largely mitigate both XSS and csrf/xsrf when properly implemented. If that's not the case or there is evidence for or against this general conclusion please call it out. Thank you! – jimmont Mar 3 '17 at 19:55
  • This is a problematic situation. if an XSS attack is occured , then satan will have the localstorage which contains the CSRF value. This should be made with an input hidden value which should be submitted every time – Royi Namir May 3 '17 at 8:06
  • 1
    Regarding to of James Ward post: jamesward.com/2013/05/13/… Cookies themselves are not the cause of CSRF vulnerabilities. It’s using the cookies on the server to validate a user that is the cause of CSRF. Just putting an authentication token into a cookie doesn’t mean it must be used as the mechanism to identify the user. What do you mean by NOT storing JWT in session? Taking above, there is no way to access cookie/session from malicious site where JWT is stored. – Rafał Łyczkowski May 7 '17 at 21:57
  • 1
    I don't think you need to store the CSRF token in the JWT payload, do you? Just store the xsrf-token in a secure cookie and let the javascript (XMLHttpRequest) set the X-XSRF-TOKEN header, then compare the cookie and header server-side. Since CSRF attacker can't set headers, it'll be fine. – Frondor Nov 12 '17 at 18:00
  • The linked article is very good in explaining the pros/cons of JWT in local/sessionStorage vs JWT in cookie, but I would not follow the last advice of storing the CSRF token in the JWT in a cookie. The CSRF token is used to protect the user from being tricked into sending an authenticated request (because the browser includes the JWT cookie with all requests). Including the CSRF token in the JWT would defeat it's purpose. Frondor has the right approach in his comment. – Dario Seidl Apr 1 '18 at 21:49
1

You could use a JWT as a CSRF token, but it would be needlessly complicated: a CSRF token doesn't need to contain any claims, or be encrypted or signed.

There is probably a misunderstanding about what JWT or CSRF tokens are used for (I was confused at first too). The JWT is an access token, used for authentication. The CSRF token, on the other hand, is used to protect the user from being tricked into sending a forged authenticated request. This is necessary when using a session or HTTP basic auth or storing the JWT in a cookie -- any authentication that is done automatically by the browser.

If you have such an authentication scheme, make sure that you

  • use proper HTTP verbs (GET must not have side-effects)
  • generate a new CSRF token on each request
  • include the CSRF token in a header or as an HTTP parameter on each PATCH, POST, PUT, and DELETE requests

Read, for example, how Spring handles CSRF.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.