JWT - Is saving the refresh token a cookie dangerous? - jwt

I've been reading about it for a few days and I have two questions
1) If I store the access token in localstorage and the refresh token in an HttpOnly cookie, do I have to worry about XSRF? If the attacker cheats to make a request, the response is received by the good user. It is not bad that it requests a new acces token and a refresh token, the attacker cannot steal the content of the response. This is true ?
If the attack is XSS it can make the same attacks as if it also stored the access token as an HttpOnly cookie ... which is bad. But if you stored the refresh token in localstorage it would be very bad and you could update the access token.
With this approach I should not worry about XSRF, but if I store the 2 tokens in HttpOnly cookie I have to worry about XSRF (about the token to avoid XSRF) and XSS. And if they make a successful attack, they can only do evil the lifetime of the access token.
2) If my authorization server is a micro service and I access through an internal IP (10.x.x.x) I have to continue worrying about XSS but not XSRF, is this true?

Have you considered saving both the refresh-token and the access-token (or id-token) to secure, httponly cookies? I do this and it works great. I also sign my cookies, and double xor them.
In your middleware function, you can check the validity of your access-token. If the access-token is valid, permit the access of the resource.
If the access-token has expired, check the refresh-token for validity (as it may be expired). If it's still valid, issue a new access-token via a cookie and permit the user access to the resource.
If the refresh-token is also expired, the user has to re-login.

I think this area is often misunderstood, and generally I recommend:
Being very careful about risks, first and foremost
Once done, store access tokens in browser memory
Refresh tokens in cookies give you better overall options
A couple of relevant blog posts of mine:
Web Architecture Goals
Browser Token Security
Interested in feedback also ..

Related

API rest with jwt for authentication. Why do we need a refresh token?

So, i'm trying nest js for a side project. Reading a lot lately about jwt authentication flow. Conceptually, the flow would be something like:
Client logs in and receives and access token and a refresh token. Access Token will be short lived and will be stored in memory, not in localstorage, to reduce the risks of being stolen.
Refresh token will be used only when the access token is expired to get a new one. The new one will be stored in memory. The refresh token will be stored in an httpOnly cookie, so no javascript access will be allowed hence improving the security.
Everything is cristal clear, but, my question is... why do we need the access token and why don't we always use the refresh token? In the end, if we are trusting the refresh token to generate new access tokens... why don't we simplify the whole thing and use only the long lived, stored in an httpOnly cookie on every request?
I mean I get the whole process, I just don't get why is not "secure" to use the token stored in an httpOnly cookie every time.
Can anyone share some light here?
Thanks!
You use the access token to access the API. It contains the necessary claims to authenticate and authorize the request.
The refresh token is a separate token that you use to renew the access token and you can not use the refresh token to access any API, as it is typically just a random string without any specific meaning (no claims).
The refresh token is never sent to any API and having separate tokens gives a better separation of concerns. By using refresh tokens, we can have short-lived access tokens, so if the access token is stolen, it can only be used for a short time. The refresh token is stored in a more secure way and it is only used between the client and the identity provider, so there is less risk that it will be stolen or intercepted.
Some platforms (like ASP.NET core) stores the token by default in the session cookie) but to secure it it is encrypted using strong encryption. This means that the hacker or browser can't see the actual tokens inside the cookie.
More you travel, more you exposed.
As you know the refresh token is meant to be used in case of short lived access token expiration. The idea for the use of two tokens is very simple. As access token (short lived token) will travel more frequently over the wire, increasing it chances of getting it caught by external parties. Therefore, short life expectency of access token will deny the access to the resouces for longer run in case of compromisation.
If the refresh token is secured, why don't we use just the refresh on
every request?
Nothing can make the refresh token secure. It's totally client responsibility to store it in secure location/storage for later use.

How do I store a JWT safely in the front end [duplicate]

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

What is the correct way to use JWT?

History
Sessions-Cookies Age: As I know JWT use for decrease DB requests. sessions are normally stores in DB and all request need query to authentication the request. In small website and web app it's not a problem but in big apps performance is very important.
JWT Rise: With JWT you can skip this step (query to DB for authentication) and can use valid JWT that's signing with your server. You should send JWT token in all request in header but if this token is stolen the thief can use it to authenticate forever.
To protect this you can add expire time in your JWT but before expire time the thief can use this as user can. Now you can decrease expire time (for example 10 mins) to protect users but after expiring the token real users should login with user and password and this is a nightmare.
The Refresh Token is born: Now we can mixed JWT with cookie concept. refresh tokens are store in DB and you can control this by login and logout. after access token (a JWT token with short age) expired clients sends request to some end point to refresh access token in this end point sever check the DB and search for refresh token. if refresh token in White list (or not in black list) the sever generate new access token and return to clients. Now you can store access token in memory and refresh token in local storage or somethings like this.
XSS attack: local storage is not safe and with XSS attacks hackers can steal your local storage.
httpOnly cookies: You can store JWT tokens in httpOnly cookies. httpOnly cookies set from server and clients can't access this from JS.
CSRF attack: New problem with httpOnly cookies is CSRF attack. CSRF attacks come from sessions-cookie age.
My approach
Refresh tokens is very similar to cookies and now we are using cookie and JWT together access token is traditional JWT token and Refresh token is traditional session's token. every 10 mins (JWT age in my example) we are login with refresh token (or session's token) and between them we use access tokens.
If users send 100 request every 10 mins my DB request for authentication decrease 100x
NOW My Question
Did I understand how to use the JWT?
Nice explanation, I think you understand it well.
To add to your explanation, you may want to rotate the refresh tokens: after a refresh token is used to obtain a new access token, return a new refresh token and invalidate the old one. This would prevent someone who gained access to the old refresh token from using it.

JWT and CSRF differences

I've been reading about JWT, and from what I understand, it's a token that the server sends after a user logs in. The user will have to send that token with all future HTTP requests. This creates a stateless way for the server to verify a user's request.
Now what I don't understand is that if the JWT is sent in the header and marked as HTTP only, why is a CSRF token also needed for prevention of CSRF attacks? My understanding is that both JWT and CSRF tokens are tied to a user, and that a JWT would serve both purposes.
I understand that CSRF tokens are used so HTTP requests from other sites won't be accepted. How does a JWT not accomplish that? What separates a CSRF token from a JWT token, and allows it to accomplish that difference?
I've been reading articles on JWT's and CSRF tokens as well as the double submit method, but there is just something I can't seem to understand or I'm missing.
An authentication system based on tokens (JWT or random) stored in cookies is vulnerable to CSRF attacks, because cookies are sent automatically to server in each request and an attacker could build a harmful url link to your site.
https://yoursite.com/delete?something=1
To protect your site it is needed to use a CSRF token that your application must send in the following request (not in a cookie).
Alternatively you could store the JWT in localStorage and send it in a Authorization header, then your site is protected against CSRF, but it could be vulnerable to XSS attacks. Take in account always the security considerations of the technical solution you choose
Update ¿why storing JWT in localstorage could be vulnerable to XSS attacks?
See this comparison between storing tokens in localstorage and http-only cookies https://academind.com/tutorials/localstorage-vs-cookies-xss
An attacker could inject javascript code to read the token from the localstorage and send it to his own server. However, this type of attack is not possible with an http-only cookie because it is not accessible from javascript
All your questions are relative to the fact that a CSRF token in NEVER included in a cookie and that a JWT token MAY be sent in a cookie.
A JWT token can be sent:
1- in a cookie
2- in another type of header
3- outside the headers, in some POST attribute
4- outside the headers, in some GET parameter (not very common)
But for stateless authentication, you MUST use cookie (case 1).
So, for stateless authentication, you are prone to CSRF, with your JWT token. This is why you need to add some CSRF mitigation mechanism, based on some more information not included in a cookie, or not only included in a cookie.
All of this would not apply if you were accepting to implement a stateful authentication.

JWT stored in cookie - security concerns

I'm building SPA app with server side rendering, using JWT-based authentication.
Current implementation is:
JWT token is issued and transferred to client after successful username and password verification
token is then stored in cookie (not HttpOnly) - the purpose of that is to avoid the need to login again after full refresh or closing page
logging out deleted cookie with token
Authorization header is attached to every API request if token exists
full SSL traffic
I can't store token in LocalStorage because of server side rendering, also the there is no HttpOnly because I need to access cookie in order to construct Authorization header.
What are the possibilities of stealing the token in such architecture?
One major risk is that any single cross-site scripting vulnerability in your application could be used to steal the token from the cookie, because it's not httpOnly (while I understand why that is the case). XSS in a javascript-heavy application like an SPA is very common and hard to avoid.
Also you're saying the token is kept in the cookie so that after closing the browser, the user is still logged in. On the one hand, that's bad practice, a user closing the browser probably expects being logged out. On the other hand, this means the cookie is persisted to disk, so it is much easier for an attacker to steal it from the client.
Another thing that comes to mind is cross-site request forgery (CSRF), but if I understand correctly, authentication is actually based on the Authorize header, where the token is copied in each request. If that's the case, CSRF is not an issue for you (but it would be, if sending the token in the cookie was enough).
So at the very least, I think you should
not use a persisted cookie for the token
try to minimize the chance of XSS (eg. by automatically scanning your code, but that will never be 100%, also by carefully choosing secure by default technologies)
make sure auhentication is based on the Authorize header and not the cookie
Still mainly because of the XSS risk, I would probably not recommend doing it this way in a security-critical application.