4

I have been working with web applications for a while, some months ago I found a possible approach to get the security advantages from Browsers while using cookies for authenticating requests, with the stateless advantages of JSON-Web-Tokens (JWT).

I'm looking to known whether this is a known and possibly broken approach.

Details:

It is well-known that cookie-based authentication can be secure against XSS but introduces the complexity of CSRF, also, JWT is handy unless you need to invalidate tokens (XSS is a problem too).

The approach:

  • When logging in, the user receives a JWT that has a very short validity period (like 3 minutes).
  • After logging in, the user also receives a cookie that allows to renew the JWT.
  • The user keeps calling the server attaching the JWT (the cookie is attached by the browser), the server authenticates the requests using this token.
  • When the server gets a expired token, it loads the session from the cookie and returns a new JWT (or the request is rejected and the user renews the token with another request), then, the original request is retried with a valid token.

Some of the advantages:

  • Token invalidation, if the JWT is ever compromised, it lives for a very short period of time.
  • CSRF protection, on a successful CSRF attack, the browser gets a new short-lived token without performing any sensitive operation on the server. - There could be lots of efficient stateless authenticated requests.
Anders
  • 64,406
  • 24
  • 178
  • 215
AlexITC
  • 41
  • 4
  • 1
    See also [Session Authentication vs Token Authentication](https://security.stackexchange.com/questions/81756/session-authentication-vs-token-authentication). – Sjoerd Mar 14 '19 at 10:22
  • Not clear how this is meaningfully different from any other session cookie + CSRF token scheme except you're basically using a jwt as the CSRF token? – Affe Mar 19 '19 at 16:57
  • @Affe the difference is that a CSRF token is used to ensure that the client is willing to do the request while the posted approach uses the JWT for stateless authentication on the request. – AlexITC Mar 22 '19 at 05:33

2 Answers2

4

Refresh tokens

This is quite similar to the refresh token pattern. In it, you have two JWTs - one short lived for ordinary requests, and one long lived for renewing the short lived one. The short lived can not be revoked, but the long lived can. This is a pattern that is commonly used, giving a good trade off between revocability and performance.

Your approach is different in that the long lived token has been switched for a cookie. Let's think some about the benefits and drawbacks of that.

CSRF

If you check that the expired token is valid before you issue a new one based on the cookie, it should technically protect you from CSRF. A CSRF attacker could not create a token, and hence not make a succesfull attack.

Still, I feel a bit uneasy about this. First, you must make a special JWT check that accepts expired tokens. That's a bit messy with room for implementation mistakes. Second, expired tokens suddenly become sensitive data. That doesn't feel so good.

XSS

You could mark the cookie as HTTP only, hence limiting the power of an XSS attack somewhat. This seems to be what motivates your scheme?

I would say this is not worth much, though. The attacker could do a lot with just the token for a few minutes. If more time is needed, just run some JS on the client constantly refreshing tokens, sending new ones to the attacker. Or just run whatever requests you want to run from the client.

Basically, if you have an XSS vulnerability it's game over. You can't really limit the impact of that with a scheme like this. You might stop a script kiddie, but not more than that.

Conclusion

I can't find an exploitable fault with your scheme, so I wouldn't label it "unsecure". But I can't really see a big benefit either. But maybe I am missing something.

What you do create, though, is more complexity. You create new patterns, new things to implement, and you mix different sort of solutions (cookies, tokens) together. It's not very clean, for a lack of a better word.

So for that reason I would go with something more standard instead, like refresh tokens.

Anders
  • 64,406
  • 24
  • 178
  • 215
  • Have you got some info on `Refreash tokens`? I gave some trouble searching for on the web... – Stefan Mar 19 '19 at 14:27
  • @Stefan It should be "refresh" without an a, I spelled it wrong first, fixed it now. Might make it easier to search! I don't have any good links right now, unfortunately. – Anders Mar 19 '19 at 15:33
  • On `That's a bit messy with room for implementation mistakes`, this applies to CSRF protection. On `expired tokens suddenly become sensitive data`, they are already sensitive unless they are encrypted. Last, I probably should have used refresh tokens in the question title, thanks. – AlexITC Mar 22 '19 at 05:37
0

For JWT tokens, there is an access token and a refresh token.

Traditionally you'd store both tokens in cookies, or both in local storage. The choice depends on which attack vector you'd like to defend against (CSRF vs. XSS).

What you propose is storing the refresh token as a cookie, but the access token in local storage -- in some ways this mitigates the attack, but I feel you're now susceptible to both CSRF and XSS, as either attack would get you a token.

My personal opinion around this, is to store both tokens onto Cookies. Using HttpOnly and Same-Site directives make cookies pretty tough to crack, especially for the refresh token where you can go all-out with a strict Same-Site directive and limit it to a very specific path on your api.

As for the access token, it depends on risk / features what same-site directive is needed.

Again, my personal view, but using a cookie only approach, allows you to forget about XSS (at least just for the tokens) and focus on CSRF. Mixing cookies and tokens would force you to guard against both.

keithRozario
  • 3,571
  • 2
  • 12
  • 24
  • You don't store anything sensitive in local storage. Ever. JWTs often hold sensitive information like username/email only Base64-encoded. – Martin Fürholz Mar 19 '19 at 14:49
  • @MartinFürholz Why not? – Sjoerd Mar 19 '19 at 15:41
  • I'm not a front-end guy, when I said local storage, I simply meant non-cookie storage. I think front-end developers differentiate between local `storage` and memory [link](https://auth0.com/docs/security/store-tokens). That being said, many apps still use the Authorization: Bearer header, which necessitates some form of non-cookie storage. – keithRozario Mar 19 '19 at 15:58
  • @Sjoerd https://security.stackexchange.com/questions/186210/how-dangerous-is-storing-the-hashed-password-in-local-storage – Martin Fürholz Mar 20 '19 at 00:24