I am using React SPA, Express, Express-session, Passport, and JWT. I'm confused about some of the different client-side storage options to store tokens: Cookies, Session, and JWT / Passport.
Do tokens have to be stored in cookies, even if I can store them in req.sessionID
?
Many websites use cookies to store shopping cart tokens. So far I have stored shopping cart data based on the session ID without adding any cookies.
So when users visit my website, I will match it with their
req.sessionID
and then retrieve the data in the database like shopping carts and user session.
Do I need to store cookies? I can access it via req.sessionID
to get the data needed.
And the second
I have made authentication using a passport-google-oauth20
.After I successfully login, the data is saved into the session. and to send it to the client I have to send it via the URL query ?token='sdsaxas'
.
in this case I get a lot of difference of opinion. someone saved it into local storage and someone saved it into cookies by converting it to a token using JWT.
jwt.sign( payload, keys.jwt.secretOrPrivateKey, { expiresIn:keys.jwt.expiresIn // < i dont know what is this expired for cookies or localstorage ? }, (err, token) => { res.redirect(keys.origin.url + "?token=" + token); });
Can I indeed store everything related to the session by using sessionID (without cookies or localstorage)?
Only by doing fetch once or every page refresh and retrieving the data and then saved into redux because I use React SPA.
Conclusion. Both cookies and localStorage are vulnerable to XSS attacks. However, cookie-based token storage is more likely to mitigate these types of attacks if implemented securely. The OWASP community recommends storing tokens using cookies because of its many secure configuration options.
To reiterate, whatever you do, don't store a JWT in local storage (or session storage). If any of the third-party scripts you include in your page is compromised, it can access all your users' tokens. To keep them secure, you should always store JWTs inside an httpOnly cookie.
There are two common ways to store your tokens. The first is in localStorage and the second is in cookies. There is a lot of debate over which one is better with most people leaning toward cookies as they are more secure.
Most guidelines, while advising against storing access tokens in the session or local storage, recommend the use of session cookies. However, we can use session cookies only with the domain that sets the cookie. Another popular suggestion is to store access tokens in the browser's memory.
This answer is based on the stateless approach and therefore it doesn't talk about the traditional session management
You have asked two altogether different questions:
As an user of an ecommerce website, I'd expect that any item I add to my shopping cart from my mobile device while commuting to my workplace, should be available in the cart when I login to the website from my PC after reaching home. Therefore, the cart data should be saved in the back-end DB and linked to my user account.
When it comes to authentication using OAuth 2.0, the JWT access token and / or refresh token need to be stored somewhere in the client device, so that once the user authenticates himself by providing login credentials, he doesn't need to provide his credentials again to navigate through the website. In this context, the browser local storage, session storage and cookies are all valid options. However, note that here the cookie is not linked to any session on the server side. In other words, the cookie doesn't store any session id. The cookie is merely used as a storage for access token which is passed to the server with every http request and the server then validates the token using the digital signature to ensure that it is not tampered and it is not expired.
Although all three storage options for access and / or refresh tokens are popular, cookie seems to be the most secured option when used in the correct way.
To understand this better, I recommend you read this and this along with the OAuth 2.0 specification.
I said earlier that cookie seems to be the most secured options. I'd like to further clarify the point here.
The reason I think browser localStorage
and sessionStorage
do not provide enough security for storing auth tokens are as follows:
If XSS occurs, the malicious script can easily read the tokens from there and send them to a remote server. There on-wards the remote server or attacker would have no problem in impersonating the victim user.
localStorage
and sessionStorage
are not shared across sub-domains. So, if we have two SPA running on different sub-domains, we won't get the SSO functionality because the token stored by one app won't be available to the other app within the organization. There are some solutions using iframe
, but those look more like workarounds rather than a good solution. And when the response header X-Frame-Options
is used to avoid clickjacking attacks with iframe
, any solution with iframe
is out of question.
These risks can, however, be mitigated by using a fingerprint (as mentioned in OWASP JWT Cheat Sheet) which again in turn requires a cookie.
The idea of fingerprint is, generate a cryptographically strong random string of bytes. The Base64 string of the raw string will then be stored in a HttpOnly
, Secure
, SameSite
cookie with name prefix __Secure-
. Proper values for Domain and Path attributes should be used as per business requirement. A SHA256 hash of the string will also be passed in a claim of JWT. Thus even if an XSS attack sends the JWT access token to an attacker controlled remote server, it cannot send the original string in cookie and as a result the server can reject the request based on the absence of the cookie. The cookie being HttpOnly
cannot be read by XSS scripts.
Therefore, even when we use localStorage
and sessionStorage
, we have to use a cookie to make it secured. On top of that, we add the sub-domain restriction as mentioned above.
Now, the only concern about using a cookie to store JWT is, CSRF attack. Since we use SameSite
cookie, CSRF is mitigated because cross-site requests (AJAX or just through hyperlinks) are not possible. If the site is used in any old browser or some other not so popular browsers that do not support SameSite
cookie, we can still mitigate CSRF by additionally using a CSRF cookie with a cryptographically strong random value such that every AJAX request reads the cookie value and add the cookie value in a custom HTTP header (except GET and HEAD requests which are not supposed to do any state modifications). Since CSRF cannot read anything due to same origin policy and it is based on exploiting the unsafe HTTP methods like POST, PUT and DELETE, this CSRF cookie will mitigate the CSRF risk. This approach of using CSRF cookie is used by all modern SPA frameworks. The Angular approach is mentioned here.
Also, since the cookie is httpOnly
and Secured
, XSS script cannot read it. Thus XSS is also mitigated.
It may be also worth mentioning that XSS and script injection can be further mitigated by using appropriate content-security-policy
response header.
httpOnly
cookie.LocalStorage/SessionStorage is vulnerable to XXS attacks. Access Token can be read by JavaScript.
Cookies, with httpOnly, secure and SameSite=strict flags, are more secure. Access Token and its payload can not be accessed by JavaScript.
BUT, if there is an XSS vulnerability, the attacker would be able to send requests as the authenticated user anyway because the malicious script does not need to read the cookie value, cookies could be sent by the browser automatically.
This statement is true but the risks are different.
With cookies, the access token is still hidden, attackers could only carry out “onsite” attacks. The malicious scripts injected into the web app could be limited, or it might not be very easy to change/inject more scripts. Users or web apps might need to be targeted first by attackers. These conditions limit the scale of the attack.
With localStorage, attackers can read the access token and carry out attacks remotely. They can even share the token with other attackers and cause more serious damage. If attackers manage to inject malicious scripts in CDNs, let’s say google fonts API, attackers would be able to siphon access token and URLs from all websites that use the comprised CDN, and easily find new targets. Websites that use localStorage are more easily to become targets.
For the sake of arguments
A pen-testing might flag your use of localStorage for sensitive data as a risk.
If it was ok for JavaScript to read access token from localStorage from an XSS attack, why do you think the httpOnly flag is still recommended by everyone.
Recommendation from OWASP
Do not store session identifiers in local storage as the data is always accessible by JavaScript. Cookies can mitigate this risk using the httpOnly flag.
https://medium.com/@coolgk/localstorage-vs-cookie-for-jwt-access-token-war-in-short-943fb23239ca
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With