Is there any benefit for storing JWT in both a cookie and local storage? - node.js

I'm attempting write an authentication system for a node.js api using express. I've noticed that if I am going to use a JWT for authentication tokens, I have two options...
1.) Store the token in a cookie, and add CSRF protection.
2.) Have the client send the token in the Auth Header and add XSS protection.
My question is, is there any benefit to storing the auth token in a cookie, and having the client send it in the Auth Header for authentication? This way if for some reason the CSRF protection fell through, the request would fail if there was no authentication token in the header. Also, if XSS protection fell through, the request would still require the auth token in a cookie. I guess my thought is that this would provide more protection, and the only way it could fail is through a successful XSS attack followed by a successful CSRF attack.
Follow up question: Are CSRF tokens a full proof protection technique against CSRF attacks?

Firstly I recommend that you go through this answer first. I hope I've bern able to address your queries about CSRF and XSS here and why and how we should use cookie.
Secondly, your approach of using localstorage along with cookie is good. The only problem I see is localstorage cannot be used across sub domains. If you use cookie and set the cookie domain as example.com (replace example with your organization domain), it will be valid across all sub domains. Thus a user authenticated by your authorization server can seamlessly login to app1.example.com and app2.example.com. You won't be able to do this with localstorage.

Related

Should JWT refresh token and access token travel together?

I'm building a SPA and i needed to authenticate users, so i decided to use JWT tokens.
To secure them on the client instead of using browser localStorage or sessionStorage i used cookies with both httpOnly and secure flags enabled.
With this configuration access token and refresh tokens travels always together.
I'm wondering if this configuration is safe or not, because if the cookies are in some way intercepted from an attacker he has the ability to also regenerate access tokens, since he has the refresh token.
In conclusion, is it the right configuration or there is an alternative way to safe the tokens with cookies without make them travel together?
Or is there any good alternative to safe JWT tokens on a SPA?
You are on the right tracks according to current best practices. When using tokens stored in cookies, aim to follow these practices also:
Encrypted cookies, eg with AES256-GCM
SameSite=strict, to prevent malicious sites from sending the cookie via CSRF
Use a path such as /refresh for the refresh token cookie, so that it is sent less often
Use a client secret for the SPA client, via its backend for frontend, which would be unknown to an attacker
Keep cookies small, ideally by issuing reference tokens to the SPA

If the JWT token for auth is saved in the HTTP-Only cookie, how do you read it from the cookie so that I can include it in request header?

I am building a Node web app using JWT for user auth.
My server sends JWT in HTTP-Only cookie via 'Set-Cookie' when user submits correct id and password, but I am stuck on how to access that JWT stored within the cookie so that I can include it in the Authorization header when making authorized API requests.
How can I access the HTTP-Only cookie from client-side to include it when sending API request to server?
Or, would it be safe to just not use the cookie at all by having the server send the JWT in response body? So that I use the JWT by putting it in a client-side variable? That way, I believe the variable is only alive until the user closes the browser.
I have looked for many resources, but was not able to find clear answer to this issue that I am stuck with.
While there are numerous ways to solve this problem, I will suggest the method where the client sends the JWT twice on each request: in an HttpOnly cookie, and also an an Authentication: header.
Let's examine what security issue each is solving:
HttpOnly Cookie
From the Mozilla documentation:
To help mitigate cross-site scripting (XSS) attacks, HttpOnly cookies are inaccessible to JavaScript's Document.cookie API; they are only sent to the server.
This is to mitigate cross-site scripting risk; imagine your website has an XSS vuln -- for example I can put <script>some_code{..}</script> into a comment, and any user who views my comment will have my code running in their browser. Yes, the attacker's code is running inside the victim's logged-in browser, but because of the HttpOnly flag, it can't extract the session cookie and send it to the attacker.
Authentication header
The problem with cookie authentication is that the browser will automatically attach them to any request to the domain that the cookie belongs to, this allows cross-site request forgery attacks. To prevent this, the usual method is to send the session token (in your case a JWT) to the client in a method other than a cookie, ie in a different header, or maybe in a hidden HTML field.
If the client is able to echo the JWT token back to you on their next request, that means they were able to read the previous response, and are not an attacker doing a blind injection CSRF attack.
Overall Suggestion
Combine the two!
The two methods serve different purposes: HttpOnly cookies protect against XSS attacks while Authentication headers protect against CSRF attacks.
There are many ways to combine them, but they all boil down to putting the JWT in some sort of authentication header, and putting a sessionID in the cookie, and having the server check that these belong to the same session. Important: remember that an attacker who achieves XSS on your site will be able to read the JWT, so for the cookie to be doing its job, the cookie should be a separate value that is not contained in the JWT. (ie if the attacker can figure out the right cookie value by looking at the JWT, then the cookie is not providing any security).

Storing "remember me" cookie and CSRF protection

I've been reading that "remember me" cookies are stored in "httpOnly" cookies, so they are not accessible by JavaScript/XSS. However, "httpOnly" cookies are vulnerable to CSRF attacks because they are sent with the request automatically.
To mitigate the CSRF attack, it is recommended to use the synchronized tokens pattern (have the server generate csrf tokens and crosscheck with the client) .
My question is, if a "remember me" cookie is available, is it possible for a CSRF attack (malicious JavaScript) to make a request and subsequently obtain the csrf token generated from the server? The concern is, if an attack has the cookie as well the token to send with requests, then the security of the app has been compromised.
If this is indeed possible, how could we prevent this?
No, the token cannot be read by another domain due to the Same Origin Policy.
If the request is made server-side to bypass the SOP, then the server isn't getting the token from the victim's browsing context therefore this cannot attack the logged in user (the server could only attack their own user that they used to get the token with).
Therefore, nothing to worry about (as long as you haven't enabled CORS of course).

JWT Refresh Token

A common scenario for user authentication follows these steps:
User registers and logs in using its credentials (username/password)
The server verifies the user's credentials and, if valid, returns an access token and a refresh token
The access token is sent on further requests and, if it is valid, the server responds with the requested resource
When the access token is no longer valid, the server requests the client to provide a refresh token in order to issue a new access token
The server receives the refresh token and two things may happen:
if the refresh token is valid, a new access token is issued to the client
if not, the server requests the user to authenticate
For the client to be able to send the access token in every request, the token should be stored either on browser storage (local/session storage) or cookies, which makes it vulnerable to XSS (Cross-Site Scripting) attacks. This problem may be mitigated if we set a short lifetime to the access token.
My question, however, is regarding to the refresh token. This token should have a long lifetime and since we use it to get new access tokens, it would be a problem if an attacker would intercept it. So storing this token on the client side might not be a good idea, right?
But, what are the alternatives?
Can we store it in a cookie set with the "httpOnly" flag? But wouldn't this make it vulnerable to CSRF (Cross-Site Request Forgery) attacks?
Is it safe to encrypt the token and still save it on browser storage?
Thank you in advance. Best regards!
which makes it vulnerable to XSS (Cross-Site Scripting) attacks.
To clarify, the cookie is only vulnerable to a XSS attack should there be a vulnerability on your site that makes this possible.
Can we store it in a cookie set with the "httpOnly" flag? But wouldn't
this make it vulnerable to CSRF (Cross-Site Request Forgery) attacks?
Although the httpOnly flag cannot be used in some forms of CSRF protection due to the need for it to be accessed client-side, flagging a cookie as httpOnly does not increase the risk to your system in any way - httpOnly is more restrictive.
Is it safe to encrypt the token and still save it on browser storage?
Not really because anyone or anything that can access browser storage can access the cookie value and present it. It doesn't matter what form it takes - encrypted or not - if it can be used directly without an external key. Don't worry about this too much - put trust in the browser to keep this secure, however ensure the rest of your site is as secure as possible.
You are right that the refresh token is viewed as more sensitive than the access token. You can store this in a cookie, however make sure that it is set to httpOnly and has the secure flag set too to ensure it is only transmitted over encrypted HTTPS connections.

CSRF Token Storage by sailsjs

I am working on enterprise solution using sailsjs as nodejs framework. Security is integral part of implementation. Apart from SSL, CORS, we are also using sailsjs CSRF implementation. I am still evaluating how secure is it to use this token. Can anybody guide on following:
Where sailsjs stores CSRF token? Is it encrypted? How secure is it to use?
You'll need to do some work to validate that your tokens are not accessible to untrusted servers; they should respond only to GET requests, and they should not but accessible via AJAX, nor should CORS headers be enabled.
PillarJS has an excellent readme on CSRF. It says about CSRF tokens:
CSRF Tokens
Alas, the final solution is using CSRF tokens. How do CSRF tokens
work?
Server sends the client a token. Client submits a form with the token.
The server rejects the request if the token is invalid. An attacker
would have to somehow get the CSRF token from your site, and they
would have to use JavaScript to do so. Thus, if your site does not
support CORS, then there's no way for the attacker to get the CSRF
token, eliminating the threat.
Make sure CSRF tokens can not be accessed with AJAX! Don't create a
/csrf route just to grab a token, and especially don't support CORS on
that route!
The token just needs to be "unguessable", making it difficult for a
attacker to successful within a couple of tries. It does not have to
be cryptographically secure. An attack is one or two clicks by an
unbeknownst user, not a brute force attack by a server.
Also consider this from Sails.js docs which gives a real-world example of how they operate:
CSRF tokens are temporary and session-specific; e.g. Imagine Mary and
Muhammad are both shoppers accessing our e-commerce site running on
Sails, and CSRF protection is enabled. Let's say that on Monday, Mary
and Muhammad both make purchases. In order to do so, our site needed
to dispense at least two different CSRF tokens- one for Mary and one
for Muhammad. From then on, if our web backend received a request with
a missing or incorrect token, that request will be rejected. So now we
can rest assured that when Mary navigates away to play online poker,
the 3rd party website cannot trick the browser into sending malicious
requests to our site using her cookies.
And finally, Sails.js uses the Connect CSRF protection middleware. Tokens are stored on a per-session basis, and therefore are not stored in a database nor is (double) encryption needed. Here's another excellent SO answer on the subject: Why does Express/Connect generate new CSRF token on each request?

Resources