23

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.

2
  • 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. Feb 25, 2016 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. Feb 25, 2016 at 19:24

4 Answers 4

14

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.

2
  • 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. May 11, 2016 at 17:19
  • Q pls @ScottJungwirth what you mean by that "you can use a user unique JWT as your CSRF" ?
    – Bruno
    Dec 23, 2018 at 16:54
28

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": "[email protected]", "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.

7
  • 1
    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, 2017 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, 2017 at 8:06
  • 2
    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. May 7, 2017 at 21:57
  • 4
    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, 2017 at 18:00
  • 2
    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. Apr 1, 2018 at 21:49
4

Please note that storing JWT in a cookie or localStorage is not the main concern. It is just as fine to store the JWT in a cookie as in localStorage, AS LONG AS the server does not look for the JWT in a cookie header. If you store JWT in a cookie called token but only accepts it on the server side in a Authorization: Bearer ... type header, you are just as safe from CSRF as you'd be when stored in localStorage, because the server side would ignore token sent in the Cookie header.

For this to work however your webapp needs to be built in a way that all valid requests are sent using JavaScript, where your JS reads the token from the cookie called token and attaches it to the outgoing request as a Authorization: Bearer ... type header.

So just note, it's not that much about where it is stored, it's more like about where it is being looked for on the server side.

3

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .