3

I think I have this sorted, but would love to hear if I'm wrong. We have a Python+Angular.js set of apps, which are using JWT tokens for authentication, where the tokens are encrypted using a secret key, the payload identifies the user, and the token is stored client side in a cookie set as HTTP ONLY and as secure. For a variety of reasons this works well for us, we get to use one Python wsgi middleware app across multiple API backends, our token gets sent automatically on every request to the domain, and we get to bypass using sessions entirely. I've had this part checked out on here and elsewhere and I'm confident it's good. ( my question on that is here: http_only for cookies with JWT tokens )

My new question is how to handle CSRF tokens, given that we are not using sessions at all. I am thinking the following:

  • auth is handled off the jwt token in the cookie described above, let's call it accept_token_cookie. JS can't read it, it's HTTP ONLY. Has the user id.
  • a second cookie is sent with our CSRF token, which is not HTTP_ONLY, thus angular can read it (let's call it csrf_cookie)
  • csrf_cookies payload is an encryption of our identity payload (or part of it, like user email), but made with a second secret key
  • when an XHR request is made, my JS will look at the csrf_cookie value, and add it to a header
  • on ingress, our server decodes both cookies and gets the token as sent by angular in a custom header. If these do not all match, we know this request is bad because the requesting javascript couldn't read our csrf_cookie. However, csrf_cookie is still not used at all to generate identity, which is what we want so that the accept_token cookie remains totally opaque to the client.

From all my reading, the above sounds correct. If I'm wrong, please tell me why, thanks.

Iain Duncan
  • 382
  • 2
  • 12
  • are your tokens for authentiction unique for each request? – hmrojas.p Dec 29 '16 at 15:09
  • When you say "on ingress, our server decodes both cookies" - is the token in a normal cookie header, and the csrf value in a custom header set by js? – Michael Jan 06 '17 at 00:00
  • Hi Michael, yes that's correct. The regular JWT token is http_only and comes in as a normal cookie. The Angular app takes the token value from the other JS readable cookie and adds it to the request headers as a custom header. The middleware compares these to make sure they match. – Iain Duncan Jan 06 '17 at 03:25
  • The authentication is not unique for each request, but rather both are set to expire in an hour and get renewed on each request. As one is readble, the client can use that one to determine how long someone has before being auto logged out. – Iain Duncan Jan 06 '17 at 03:26
  • edited original question to clarify the comparison is of a custom header and the values in the cookies. – Iain Duncan Jan 06 '17 at 03:30

1 Answers1

1

when an XHR request is made, my JS will look at the csrf_cookie value, and add it to a header

If you are not using CORS and you are checking this header server-side then this alone will be enough to mitigate CSRF.

The reason is that custom headers cannot be sent cross-domain without CORS.

Setting and checking the actual token value helps further because any vulnerabilities present in plugins (e.g. Flash) that may help bypass the custom header restriction cannot be leveraged to bypass your protection.

See here for using custom headers as a CSRF mitigation.

Your approach seems like a variation of the Encrypted Token Pattern.

SilverlightFox
  • 33,408
  • 6
  • 67
  • 178