JWT tokens in sessionStorage vs cookies? - javascript

There are a lot of blog posts from Stormpath that talk about how you ought to use cookies to store your JWT instead of sessionStorage/localStorage:
https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage
https://stormpath.com/blog/token-auth-spa
https://stormpath.com/blog/build-secure-user-interfaces-using-jwts
The main stated reason is that if a 3rd-party javascript dependency that you load is compromised that it can pilfer through sessionStorage/localStorage and transmit off the JWT to somewhere.
But this is confusing as a reason to me. I understand the attack vector, but if you have a compromised 3rd-party javascript dependency, aren't you effectively screwed anyway, since it can listen-in/capture anything your users do as they interact with your app?

I'm the author of https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage
When XSS exist on a page, an attacker is privileged to:
HTML5 web storage (local and session)
Cookies that are not set with httpOnly flag
Control of the tab until it is closed and the ability to make unauthorized requests
You can also start to formulate attacks to get around XSRF protection.
When an XSRF vulnerability exists, an attacker is privileged to:
Making unauthorized requests from a 3rd party domain, if you can lure a user there (or send them there in the presence of XSS).
You can see that when an XSS vulnerability exists, you are able to make unauthorized requests and an attacker would need to jump through some more hoops to exploit XSRF. This means that when XSS exists (regardless of XSRF protection or not), the attack vector of making unauthorized requests will exist.
Hopefully, that clears things up for my next point.
An XSRF attacks or unauthorized requests has less impact and scope than stealing a stateless token that represents the user's identity and session. Leaking the token means that an attacker will have full control to formulate an attack on behalf of the user, on his time, on his machines.
In conclusion, in presence of XSS when you:
store an access token in web storage, the tokens for any user that uses your site during the time of the existence of XSS is compromised. This means an attacker could get thousands of valid access tokens and can possibly do a lot of harm (even more if you store refresh tokens in web storage). The users are also vulnerable to making unauthorized requests from their own browser.
store an access token in a httpOnly cookie, the tokens for any user are not compromised. But, the users are also vulnerable to making unauthorized requests from their own browser even in the presence of XSRF protection.
Hope this information helps.

Related

Where do I store the refresh token and access token and how do I use it?

i can't easily decide how to receive the refresh token and access token from the back-end and where to store it.
the authentication process I understand is as follows.
XSS can be defended with cookies.
using cookies is vulnerable to CSRF.
however, in the case of cookie, it can be stolen as 'document.cookie'. So, use the 'httponly' option to prevent access from javascript.
cookie is always included in header when making http request, so it is vulnerable to CSRF. So, when logging in, 'refresh token' and 'access token' are created in the back-end, stored in the DB, and returned to the client.
request an api using an access token, and if it expires, update it using a refresh token.
as I refer to many articles, it is said that XSS is to be blocked with cookies and CSRF is to be protected with refresh tokens and access tokens.
and in the case of refresh token, it is stored in webStorage.
however, in order to prevent XSS, it seems that in the case of access tokens, cookies should be used to protect them (+ httponly applied), and in the case of refresh tokens, it seems that they should be stored in the client.
if the refresh token is sent in a cookie with the httponly option, isn't it accessible from the client?
in conclusion...
in the back-end server, should the access token be sent as a cookie and the refresh token included in the body?
Any ideas would be appreciated.
The tokens are usually sent back in the body of the response. This way your frontend app can easily read them and store wherever needed. Usually storing them in memory should be enough (in a variable or state of your app, etc.). When the user refreshes the page they will have to log in again, but that should not be a problem if the Authorization Server supports things like "remember me". If you're using an OpenID Connect-compliant Authorization Server, then you can perform a silent login - so obtain tokens without the need of redirecting the user anywhere.
If you store your tokens in a http-only cookie then your app will not have access to them, so you won't be able to call any APIs from your app. I think this is not what you're trying to achieve.
Keeping the tokens in memory could help you be a bit more safe from XSS attacks, but you will never be 100% secure. Have a look at this talk: https://pragmaticwebsecurity.com/talks/xssoauth.html where it is explained. In fact the only way to be sure that an XSS attack can't steal your tokens is to keep the tokens in a backend app, not in the browser.

Where and how save token JWT ? (Best Practice)

I've read that save token JWT in localStorage is a bad practice.
https://dev.to/rdegges/please-stop-using-local-storage-1i04
I'm working with ReactJs, and to other side have a API Rest with NodeJs.
Where and how I should save token JWT ?, in a Cookie?
Gretting from Chile,
If the choice is between cookie and localStorage, both have their pros and cons when it comes to security. With all security attributes set correctly (HttpOnly, secure, SameSite=strict) it is true that a cookies could be more protected against certain attacks.
However, SameSite attributes may not work for everyone, and may not protect all functions against CSRF (Cross Site Request Forgery) attacks.
HttpOnly will protect the value from being accessed from JavaScript which is good if the application suffers (XSS) Cross Site Scripting vulnerabilities. However, any moderately qualified attacker could easily achieve what they wanted without accessing the actual value of the token anyway.
The thing to remember when storing tokens in localStorage is that it is not cleared when the browser is closed, meaning that a user will not become logged out by closing the browser - which many have come to expect. If that is a problem, you may want to consider storing the JWT in the sessionStorage instead.
localStorage seems fine because many people are using localStorage.
If you want extra security feature
You can make your token lifespan short eg {30 min, 60 min}
Also You can check your user active state whether or not
The user will Logout automatically

JWT with SPA without a server

The application is a SPA that is hosted on static storage (conceptually similar to S3, although it's not S3) and has no backend server at all. Assume this is https://static.example.com/app.html
When users visit the page, they can authenticate with an external provider like Auth0 and Azure AD. They complete the authentication flow and are sent back to the SPA with an id_token on the URL fragment. For example, https://static.example.com/app.html#id_token=XX. That id_token is used to call an external API server, passed in the Bearer authorization header.
The issue is where to store the JWT in the client.
It's a known fact that storing the JWT in sessionStorage could lead to the tokens being stolen with XSS attacks (or malicious code added in a dependency, etc).
The recommended approach would be storing the JWT in a cookie that is set to HttpOnly, or at least part of it (see the "Cookie Split" section). However, this is not doable in my case, as there is no backend server, and after being authenticated users are redirected to the SPA directly, so I can't create a HttpOnly cookie. A variant of this method is what OWASP recommends: using a "fingerprint cookie". This has the same issues since I can't set a cookie that is HttpOnly.
Another approach, as for example suggested by the Auth0 documentation, is to keep the JWT in memory. While this should prevent theft with most (if not all?) XSS attacks, it's unpractical because the session would be limited to the current tab, and would not survive a page reload.
I see two different options, all with serious or potentially serious drawbacks:
Store the token in sessionStorage anyways, assuming the risk that in case of XSS attacks (or a malicious dependency injected via NPM) could lead to sessions being stolen. This could be mitigated by setting a short lifespan to tokens (e.g. 1 hour). While the app I'm working on doesn't store critical information (it's not banking or similar), a mistake in the code that let sessions to be stolen via XSS would not be nice.
Implement a backend server to move the authentication flow there, maybe even replacing JWT's with session tokens entirely. This would make the application not static anymore, however, and it's undesirable.
(The third option, keeping the JWT in memory, is excluded because of the poor user experience)
What am I missing?
Security is a compromise - you can choose to accept the risk of XSS, or to take the burden of a backend server for more security, or to sacrifice user experience for a level of security probably inbetween the two. You can't have everything.
One usual solution is to have very short-lived tokens in sessionStorage, and an httpOnly cookie for the identity provider to get a new token when needed. This way stealing a session token provides less value for the attacker, and as XSS needs user interaction, it may sometimes be difficult for an attacker to get hold of a new one (or easy, depending on where the XSS is). Also this solution needs more graceful error-handling and results in slightly more complex code.

CSRF - Is it safe to ask it with api call?

I'm using session based CSRF on a site using Angular. Is it safe to make an HTTP call to ask for the CSRF token?
For example, if I sent a request with valid user session to a page called /csrf/get and it prints a raw token, is this secure enough for CSRF functionality? If not, is there anything I can do to make it more secure while keeping the JSON retrieval functionality?
It will be the first api call before everything else and I will keep it on localstorage to use it on every http call
In short, no. The way that you are trying to do CSRF protection exposes you to CSRF since your csrf/get endpoint is not protected from CSRF.
Essentially, you need to protect yourself from two main attack vectors: XSS, and CSRF.
CSRF
CSRF involves your site and a malicious site that will attempt to make authenticated requests to your site. If there is a way to request a CSRF token from the malicious site, you are not protected.
Usual methods for protecting from CSRF are by returning a token from your authentication API call, and storing that token in the browser session. The problem with this method is that it opens you up to XSS.
XSS
Cross-Site scripting, or XSS vulnerabilities are related to external scripts running on your page. This includes potentially malicious scripts inserted by an attacker.
Local storage and session storage are not safe, so you shouldn't store a token in regular cookies, for example.
To be safe from XSS attacks Your authentication response can store cookies that javascript can't read by using HttpOnly cookies.
So, using a token that you store with javascript protects you from CSRF, but opens you up to XSS, where using a session cookie protects you from XSS, but opens you up to CSRF.
Protect your API from XSS and CSRF
The solution is to use both approaches: your authentication API should set an HttpOnly cookie to protect from XSS, and should return a token to protect from CSRF.
Note that there's no need for a csrf/get api since the token should be returned by the authentication method: you want to only send that token in exchange of valid credentials. Remember to also send and validate that same token on all authenticated API calls.
Here is a great article explaining API security, why and how to do it in much more detail:
http://www.redotheweb.com/2015/11/09/api-security.html
Note on login CSRF:
Logic forms should also be protected from CSRF by creating pre-sessions with CSRF tokens.
(from https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#login-csrf)
Most developers tend to ignore CSRF vulnerability on login forms as they assume that CSRF would not be applicable on login forms because user is not authenticated at that stage, however this assumption is not always true. CSRF vulnerabilities can still occur on login forms where the user is not authenticated, but the impact and risk is different.
For example, if an attacker uses CSRF to assume an authenticated identity of a target victim on a shopping website using the attacker's account, and the victim then enters their credit card information, an attacker may be able to purchase items using the victim's stored card details. For more information about login CSRF and other risks, see section 3 of this paper.
Login CSRF can be mitigated by creating pre-sessions (sessions before a user is authenticated) and including tokens in login form. You can use any of the techniques mentioned above to generate tokens. Remember that pre-sessions cannot be transitioned to real sessions once the user is authenticated - the session should be destroyed and a new one should be made to avoid session fixation attacks. This technique is described in Robust Defenses for Cross-Site Request Forgery section 4.1.
First of all, use https, http is unsafe.
Then, better not to use GET.
Safe way is to send token in successfull auth request's (POST) response.
For more info, check:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

How can I secure my website from injections (Cookie editing)

I'm using cookies in my Java EE application (jQuery on the client) and while taking security as a key point, I came to know that one can read the cookies and edit them by reading article's. I'm really want to make application out of these attacks.
I read How to prevent Javascript injection attacks within user-generated HTML on SO and didn't find a solution to make my cookies secure.
There are several flags you can set for cookie to mitigate the security risk.
The secure flag. It mandates that cookie should only be sent through https. This is important, even when your site is using https. Why? Let's say a bank site forces end user to use https. The user connects to the bank site through https, login successfully. The bank site sends the cookie back to the user browser through https. Assuming a hacker can sniff the network and see all the cleartext communcation between the end user and the bank site. Obviously for now, the hacker cannot see anything, as the cookie is transmitted through secure channel. Here is what the hacker can do if the HttpOnly flag is not set
a) The hacker creates a site www.maliciouscode.com.
b) He sends an email to the end user with the link, luring the end user to the site.
c) The user takes the bait, connecting to http://www.maliciouscode.com site through another browser tab.
d) The malicious site redirects the user browser to the bank site through http.
e) The user browser sends the cookie through HTTP to the bank site.
f) The hacker intercepts the cookie since it is sent as cleartext, places it in his own browser and login as the user
The HttpOnly flag. The name is misleading. It is not the opposite of the secure flag. It means the cookie should only be used by browser through http (and https) protocol only, but not used by other means such as JavaScript. If a browser that supports HttpOnly detects a cookie containing the HttpOnly flag, and client side script code attempts to read the cookie, the browser returns an empty string as the result. This is to prevent the XSS attack.
Unless there is some other vulnerability in your site (or the user's system), there is no way for a third party to modify cookies.
Therefore you can treat them exactly the same as you would any other data that comes from the client (except that you don't need to worry about cookie data being faked with a CSRF attack). That is to say: Trust the cookie as much as you trust the user.
Cookies are not secure. Forget protecting them.
You should protect your server by having all communication on HTTPS. HTTPS protects your cookies more than anything else (it cannot protect against Session Hijacking though).
Do not store any sensitive information in the cookie other than the session id.
Make sure your cookies are configured as HTTP ONLY. If not, the session id will be sent as a part of the query string and can be intercepted (and cached) by any one.
Regenerate your session id on major events like user login, password change, etc.

Categories