Should JWT be stored in localStorage or cookie? [duplicate] - security

This question already has answers here:
Where to store JWT in browser? How to protect against CSRF?
(7 answers)
Closed 2 years ago.
For the purpose of securing REST API using JWT, according to some materials (like this guide and this question), the JWT can be stored in either localStorage or Cookies. Based on my understanding:
localStorage is subjected to XSS and generally it's not recommended to store any sensitive information in it.
With Cookies we can apply the flag "httpOnly" which mitigates the risk of XSS. However if we are to read the JWT from Cookies on backend, we then are subjected to CSRF.
So based on the above premise - it will be best if we store JWT in Cookies. On every request to server, the JWT will be read from Cookies and added in the Authorization header using Bearer scheme. The server can then verify the JWT in the request header (as opposed to reading it from the cookies).
Is my understanding correct? If so, does the above approach have any security concern? Or actually we can just get away with using localStorage in the first place?

I like the XSRF Double Submit Cookies method which mentioned in the article that #pkid169 said, but there is one thing that article doesn't tell you. You are still not protected against XSS because what the attacker can do is inject script that reads your CSRF cookie (which is not HttpOnly) and then make a request to one of your API endpoints using this CSRF token with JWT cookie being sent automatically.
So in reality you are still susceptible to XSS, it's just that attacker can't steal you JWT token for later use, but he can still make requests on your users behalf using XSS.
Whether you store your JWT in a localStorage or you store your XSRF-token in not http-only cookie, both can be grabbed easily by XSS. Even your JWT in HttpOnly cookie can be grabbed by an advanced XSS attack.
So in addition of the Double Submit Cookies method, you must always follow best practices against XSS including escaping contents. This means removing any executable code that would cause the browser to do something you don’t want it to. Typically this means removing // <![CDATA[ tags and HTML attributes that cause JavaScript to be evaluated.

A timely post from Stormpath has pretty much elaborated my points and answered my question.
TL;DR
Store the JWT in cookies, then either pass the JWT in the Authorization header on every request like I've mentioned, or as the article suggests, rely on the backend to prevent CSRF (e.g. using xsrfToken in case of Angular).

Do not store your token in LocalStorage or SessionStorage, because such token can be read from javascript and therefore it is vulnarable to XSS attack.
Do not store your token in Cookie. Cookie (with HttpOnly flag) is a better option - it's XSS prone, but it's vulnarable to CSRF attack
Instead, on login, you can deliver two tokens: access token and refresh token. Access token should be stored in Javascript memory and Refresh token should be stored in HttpOnly Cookie. Refresh token is used only and only for creating new access tokens - nothing more.
When user opens new tab, or on site refresh, you need to perform request to create new access token, based on refresh token which is stored in Cookie.
I also strongly recommend to read this article: https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/

To help prevent CSRF attacks that take advantage of existing cookies, you can set your cookie with the SameSite directive. Set it to lax or strict.
This is still a draft and as of 2019 is not fully supported by all current browsers, but depending on the sensitivity of your data and/or your control over the browsers your users use, it may be a viable option. Setting the directive with SameSite=lax will allow "top-level navigations which use a 'safe'...HTTP method."

Related

Is it better to split a bearer token in half between cookies and localstorage?

I wanted to save a bearer token to authenticate APIs on the client. I read that http-only cookies and localstorage have different downsides, and felt that using both at the same time would improve security.
Would it be wise to save half of the token in an http-only cookie and half in localstorage, or should I only use one of them?
With SameSite being set to Lax or Strict, the cookie will get the CSRF protection that was the primary weakness that caused a move from cookies to bearer tokens. A cookie that is set to Secure, HttpOnly and SameSite=Lax/Strict will only be sent on HTTPS, not be available to script and have a decent protection against CSRF.
Bearer tokens saved in local storage will be accessible to script, and can thus be stolen in XSS attacks, just as with cookies lacking the HttpOnly flag.
If you store half in local storage and half as a cookie you are probably going to combine the parts before using it in a request header. In this case you can't set HttpOnly flag on the cookie, and you will lose the benefits that cookie storage can provide. Consequently it doesn't make sense to split the bearer token.
If you are in this situation because you use the implicit code flow of OAuth 2.0, please be adviced that this flow is now deprecated and you should use Authorization code with PKCE flow instead, and your authentication token should be stored in a cookie hardened as described above.

A secure single site JWT implementation

I read a lot about JWTs and found that it is pretty hard to use them in a secure CSRF and XSS proof way.
Until I realized that my tokens will probably not leave my unique domain...
This led me to this idea of implementation:
Use a refresh token along with an access token. That way I can set short expiring time to the access token and limit the database calls to verify the user and only when the access token expires a simple verification by asking the database that the refresh token is not blacklisted before sending a new access token to the user.
I understood that if I store a token in the local/session storage it would be vulnerable to XSS attacks but if I store it in an HTTP-only cookie it would be vulnerable to CSRF attacks.
As I don't need to access the token inside the JavaScript and that I only need this token in one website, I thought that I could store the access token inside an HTTP-only cookie (that way it is protected from XSS) along with the secure flag and the same site flag set to strict (preventing CSRF).
And regarding the refresh token I could store it inside an HTTP-only cookie that has the same secure flag but without the same site flag this time. Because the server will never execute any action only based on the refresh token, I think that it will therefore not be susceptible to CSRF attacks. The only thing the server will do with a refresh token is to send back a new access token which, if I understood it well, could not be read from the CSRF attacker. The CSRF vulnerability allows the attacker to make a request to the server (which will automatically contain HTTP-only cookies) but he cannot read the response of this request.
I don't know if this implementation of JWTs would be secure or if I missed something...
This is what I'm asking you (JWTs and web security experts) would that be a good JWTs implementation ?
First, a word on JWTs. An oldschool plain server-side session (with a long, random session id, correctly stored in a secure, httpOnly, maybe also SameSite cookie) is "more secure" than any JWT in most cases. The reason is that JWTs store state on the client, where it is more available to an attacker, offline attacks can be performed against the cryptography involved, also JWTs are plain text and only their integrity is protected (ie. they are protected against client-side change, but not against looking at the contents by default, though you could use JWE, and encrypted JWT too). Last but not least, implementation is more complex, and simplicity is great for security.
So you would use a JWT when you need a benefit that it provides.
One argument is that it's stateless. This is very often overrated though. First, in most applications the bottleneck will not be the database lookup needed to find the session data in the database. In some very high profile, high traffic applications it actually might be, but you are probably not developing something like that every day. Usually it's just ok to do a database lookup, and it makes the whole thing a lot simpler. Second, sometimes you need token revocation, ie. you want to be able to force-logout a user. Even if you used a JWT for statelessness, you would have to store something in a database, a list of revoked tokens for example, and checking that would also be a database roundtrip. Revoking JWTs simply cannot be implemented in a purely stateless way.
Another benefit is that you can use it for multiple origins. If you get a httpOnly session cookie, that will be managed by the browser, javascript cannot send it to other origins, like an API or something - that's the whole point, JS not having access. But sometimes you do need that, especially in single sign-on scenarios, where you have an identity provider (a component that provides logon), and services (eg. APIs) that you want to use your access token on. In this case a classic cookie would not work, and JWTs are very handy.
So in short, you would use a JWT when you really need statelessness, or the option to send the token to multiple origins. As a rule of thumb, if you can store the JWT in a httpOnly cookie, you most probably don't need it at all, and could just use a plain old server-side session.
And then let's say you decide to use JWTs, what about refresh tokens. They are another generally misunderstood feature of token-based authentication. The point in using refresh tokens is to be able to use short-lived access tokens, so if an access token get s compromised, it is at least time limited. But if you store the refresh token the same way as an access token, why would an attacker not get that too?
It only makes sense to have a refresh token, if you store it differently, otherwise you could just have long-lived access tokens, and that would not be less secure.
One typical thing is to have an identity provider ("login server", or IdP) that sets a refresh token (or just a plain old session id) in a httpOnly cookie for the identity provider origin, so whenever the client makes a request to the IdP, it "just works" if they are already logged in, and can provide a new access token without user interaction. The access token is then stored in something like localStorage (for the service origin), susceptible to XSS, but at least time limited. If you don't have this separation, a separate refresh token probably doesn't make much sense.
As a final note, all of this should very rarely be implemented by yourself. Any language or framework you use probably already has one or more known good, maintained implementation for authentication. You should just use those, but it's still very much worth to understand it of course.
Please note that in any actual application there might be subtleties and certain circumstances that somewhat change what you want to do, but the above is a general way to think about secure authentication.

Is it dangerous to store a JWT in a Javascript-accessible cookie

In other words, is it dangerous to have a JWT, which doesn't contain any sensitive info, in a cookie without the httponly flag? I understand the main security concern is XSS attacks. So since Javascript can access the cookie, attackers can potentially access the token. But since there isn't any sensitive info in the JWT, is the only harm session hijacking?
The crux of the issue is that I would like the JWT to be in a Javascript-accessible cookie because I want to be able to access the token claims to limit the functionality of the user within the ui.
So is it a better idea to use a non-httponly cookie for the JWT, or make the JWT in a httponly cookie and just do a separate non-httponly cookie for storing the user's credentials?
Although the JWT does not contain any sensitive information, the token itself is sensitive. JWTs are usually used as bearer tokens, which means they are a (possibly time limited) credential that can be used by anyone in possession of the token to access whatever resources the token is issued for.
An attacker who was able to obtain the token via a successful XSS would therefore be able to impersonate the victim to make requests to your server. This is what you describe as "only" session hijacking. I'm not sure why you say "only". Usually session hijacking is pretty serious ;o)
A more secure approach in my opinion, as you say, to make the JWT cookie HTTP-Only and have a separate cookie containing the information used to limit the functionality in the UI.
As an aside, limiting the UI in this way should not be considered as an effective security measure on it's own, since it would almost certainly be possible to bypass the UI restrictions unless they were also enforced on the server side. It is fine to use it for personalisation of the UI though.

How to implement anti CSRF token protection with multi tab support?

I have an application in which I would like to implement protection against CSRF using a security token, but also to make my application available for that same user if he opens a new tab.
When the user authenticates himself with his correct username/password combination, I add him to the session and return a cookie that contains the token. When the cookie arrives, I remove the token from the cookie and store it in a global variable. With each request I make I append the token and compare it with the one on the server.
The problem is when I open a new tab, user gets automatically removed from the session because a request that doesn't contain a correct token is received.
I understand that if I store that token in the cookie or in the localStorage I would be able to read it from another tab and the request will be valid, but I'm not sure how safe is this implementation or even which one is better? With a simple XSS you could read the token from the cookie/localStorage/global variable...
Are there any other ways I can implement a CSRF token protection and still be able to use my application from another browser tab?
With a simple XSS you could read the token from the cookie/localStorage/global variable...
If your site is vulnerable to XSS then this always supersedes any CSRF vulnerability.
As long as CSRF tokens are refreshed for every new session, there is no need to change the CSRF token once it has been used. An attacker cannot read the token so there is no extra risk.
This will enable tokens to work across tabs with no loss in security.

How to persist bearer token on client side

I'm trying to get my head around claims based authentication in ASP.NET Web API 2. In my application I use the VS 2013 template, which implements OAuth 2.0 and uses bearer token (JWT as I remember). My question is - what is the best way to persist token on the client side. In his book Badrinarayanan Lakshmiraghavan describes bearer token as
A bearer token is like cash: finders, keepers.
Therefore, is it safe to save it to a cookie? Doesn't it mean that whoever will steal the cookie will get full access to the application? On the other hand I could encrypt the token using hash just before saving it to the cookie. Would it be safe enough? Are there any other alternatives? I've seen few questions asking similar question on stackoverflow, but have never found satisfying answer.
is it safe to save it to a cookie?
No. Cookies can be stolen via XSS attacks (and other vectors)
Also, this might be susceptible to CSRF since a cookie will be submitted automatically with any request.
I could encrypt the token using hash just before saving it to the cookie
This will also not work. Hashing is not a secure way to encrypt (and moreover does not allow decryption)
Are there any other alternatives?
Basically, you should give the token to the user over a secured connection (HTTPS) but they should manually submit it for security (again over HTTPS)

Resources