We are doing an Html5 AngularJS application. We are using token based authentication. The authentication process logs the user in then a JWT Token is returned to the application which is stored in sessionStorage.
We requested a security audit on the application and the tester said that it is a big problem that the token is stored in the sessionStorage. Because he can copy the token and impersonate a user from another device.
Where and how should I store this token to make sure that it is secure ? Is it even a risk leaving it in the session storage since the hacker would need access to the actual device to perform this attack
regards
One way to increase security on token storage is to store the token in a Cooke with the HttpOnly flag set. This would mean the token could only be accessed when your app makes http requests.
Related
I am using a JWT authentication scheme for my app. I did some research about how to store and use access and refresh tokens, and I have several questions that I couldn't really find an answer to. For the app, I am using React for the frontend and .NET 6 Web API for the backened.
Question 1: Storing what where?
Based on the research I did, local storage is not a good place to store a jwt token for security reasons. So probably the second best alternative would be HttpOnly cookie for the jwt token and local storage for the refresh token. However I did read some articles where jwt token is stored in local storage while the refresh token is stored as HttpOnly cookie. Which approach is better, and the pros and cons of each. P.S I will be rotating the tokens, i.e a new access and refresh token will be generated once the old jwt token is refreshed. Or even store it in memory such as redux state
Question 2: When to refresh JWT Token?
Should the jwt token be refreshed just before it expires, such that the backend can verify the token, or is it fine to refresh the token after it expires (by bypassing the verificatoin when refreshing the token only i.e the refresh endpoint). Also should refreshing, be done by setting an timer/interval, or waiting for a request to fail?
Question 3: Accessing User Data and Expiry Date
I am storing some user data, such as username and password in the jwt token so I can acees them in the frontend. The problem is that when setting the jwt token as HttpOnly cookie, since Javascript can't access the token, I won't be able to access user data and the token's data(such as jti and expiry date). For the user data, I could do a seperate request to access user data such as username and email, but for the JWT token's expiry date, how could I obtain it?
I would appreciate answers to these questions or any feedback if someone faced similar issues and how you resolved them
Consider these as discussion rather then guideleines
Question 1: Storing what where?
Storing access tokens in memory is a good choice
But if you have a refresh token, and you need to do a silent login, local storage is the only choice
but you can always encrypt the token before storing
Question 2: When to refresh JWT Token?
if you wait for token to expire and then refresh with refresh token then existing request which failed with expired token need to be queued again.
if you refresh token on regular intervals, if existing token is invalidated with refreshing, then again the same issue failing requests needing to be queued again.
if you are using axios, you can use libraries like axios-auth-refresh, which will queue the failed requests and try then again with a new token.
you can check their source code or may be create your own version if handling failed calls is important.
Question 3: Accessing User Data and Expiry Date
Access token and cookies should not contain sensitive information
its better to make another call to the api to get users info
Question 1: Storing what where?
First, it is never recommended to use refresh tokens if you are not able to store them securely. Consider building a traditional web app instead.
Second, session storage is always recommended over local storage for these types of tokens.
However, I understand the problem and there are ways to get around this with “Secure SameSite Cookies” if both your apps use the same domain name. OWASP has recommendations, have a look at “token side jacking”: https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html
A simplified version below (please read OWASP recommendation and make the necessary adjustments):
During the authentication face (Web API):
create a “user context”, a random string
set access token with “user context”
set refresh token with “user context”
set http response header with a hardened cookie (flags: HttpOnly + Secure + SameSite + cookie prefixes). Value: “user context”
You need to implement validation of “user context” for API requests and for the refresh token flow; if “cookie user context” does not match “token user context”, then respond with proper http error code.
This makes it possible to:
store access token in session storage
store refresh token in local storage
Question 2: When to refresh JWT Token?
Should the jwt token be refreshed just before it expires, such that the backend can verify the token, or is it fine to refresh the token after it expires (by bypassing the verificatoin when refreshing the token only i.e the refresh endpoint).
If access token has expired then try refreshing tokens using your refresh token. If refresh token has expired, then a new authentication is needed. The definition of an expired token is that it is no longer valid and cannot be used.
Also should refreshing, be done by setting an timer/interval, or waiting for a request to fail?
Wait for the request to fail. If both access token and refresh token has expired, then a new authentication is needed.
Question 3: Accessing User Data and Expiry Date
It is not recommended to store sensitive information in access token. The access token should be opaque to the client application. Set access token with some identifier and create a /userinfo endpoint that returns information about the user. Eg, Create an authController with two actions:
/token (used for authentication)
/userinfo (used for retrieving information about the user)
I've spent a few days trying to figure out a secure authentication method for SPA/React (client-side).
Most of the tutorials I've read in the wild contradict each other.
One says have to store in Cookies another in Local Storage, one says don't need to use refresh token, one says have to use a refresh token.
I'm building a React SPA app for the frontend and Express for the API (backend). Both are stored in the same domain:
React: example.com
Express: api.example.com or example.com/api
Is it enough to secure my application by using Cookie (access token JWT):
httpOnly:✅
secure: ✅
sameSite: strict
without refresh token
This matches the answer here: https://stackoverflow.com/a/57779076/11340631
The question is:
Is this safe enough?
How long does it take to set the expiration of the access token?
Is this as per Oauth recommendation?: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps
What if my access token is stolen? For example, my friend is using my PC and he stole my cookies and use it in his PC browser.
I really hope to get the answer here, any answer is appreciated.
It's safe against extracting the token with Cross Site-Scripting, but, without other security controls it might be prone to Cross Site Request Forgery (cookies are automatically attached to a request). Is API accepting key in the cookie or must it be sent in the Authorization Bearer header?
My concern is, that if you're not using refresh token, the access token must have a relative long expiration. OAuth2 was not intended to be used to authentication alone, but together with some session-like solution, for example OpenID Connect and SSO.
The shorter the better, unless it can be revoked any time server-side. If there's no way to revoke the key, the 5 minutes expiration date is, in my opinion maximum. That's why refresh token and session-like endpoint is the must.
OAuth is not designed for web application client's authentication at all. That's the common anti-pattern in many projects I've pentested. https://oauth.net/articles/authentication/
I'm glad for your awareness of such a threat. Access tokens must either live very shortly, or they must be revoked server-side in a some way, for example by utilizing some kind of revoke-list. Or the refresh token with server-side-like session endpoint should be utilized.
I had an identity server 4. When I tried to lock a user, the user still can access APIs, because the JWT token seems still valid.
What should I do?
Once a JWT is issued, it stays valid until it naturally expires (exp claim in the token).
To invalidate it before that expiration, you would need to revoke it. This approach is similar to X.509 certificate revocation. The identity provider would have to track a list of revoked tokens. That revocation list (preferrably secure hashes of revoked tokens) can then be:
asynchronously distributed over a channel (e.g. Kafka)
exposed over a service (query list of revoked token hashes, or query if a single JWT is revoked). This poses a significant overhead for JWT verification, as an additional service call is required on each request.
The simpler and recommended solution would be to limit the validity of the JWT (to, let's say, 10 minutes), and use refresh tokens (in a HTTP-only cookie) to refresh the JWT before it expires.
The best thing is to use short-lived access tokens and use the refresh token to renew the access tokens. Doing a lookup in the API that receives the access token on every request will be pretty expensive performance wise. So
So, its all about what trade-offs that you are willing to make.
I am a newbie to Azure AD. What is the best practice for using Azure AD access tokens?
What is the difference between an 0Auth and JWT token and which one should I use to follow best practices?
I used the below code to get the Token. Do I need to convert it to an 0Auth Token?
var AzureData = await DependencyService.Get<IAuthenticator>()
.Authenticate(App.tenanturl, App.GraphResourceUri, App.ApplicationID, App.ReturnUri);
App.AuthenticationResult = AzureData;
var userToken = Azuredata.AccessToken;
Please help. Thanks.
JWT is a type of Token, and OAuth is a Framework.
JWT (JSON Web Tokens) is just a token format, it defines a compact and self-contained mechanism for transmitting data between parties in a way that can be verified and trusted because it is digitally signed.
Oauth is an authentication framework, where it has a general procedures and setups defined by framework. JWT can be used as a mechanism inside OAuth. You do not need to convert your token.
Use JWT when...
Federation is desired. For example, you want to use Azure AD as the token issuer, and then use Apigee Edge as the token validator. With JWT, an app can authenticate to Azure AD, receive a token, and then present that token to Apigee Edge to be verified. (Same works with Google Sign-In. Or Paypal. Or Salesforce.com. etc)
Asynchrony is required. For example, you want the client to send in a request, and then store that request somewhere, to be acted on by a separate system "later". That separate system will not have a synchronous connection to the client, and it may not have a direct connection to a central token dispensary. a JWT can be read by the asynchronous processing system to determine whether the work item can and should be fulfilled at that later time. This is, in a way, related to the Federation idea above. Be careful here, though: JWT expire. If the queue holding the work item does not get processed within the lifetime of the JWT, then the claims should no longer be trusted.
Use OAuth when...
There is no federation. The issuer of the token is the same party that validates the token. All API requests bearing the token will go through the token dispensary.
There is no need or desire to allow the holder of the token to examine the claims within the token.
When you wish to unilaterally allow token revocation. It is not possible to revoke JWT. They expire when they are marked to expire at creation time.
See this thread for more details.
I am using Passport-local on Node.js (saving user info in Mongodb) and Angular.js as the client. The process is easy.
However here are 3 security concerns:
When I do the login on the client, a json file with user and real
password are sent to the server.
After I login, the token will be saved in the Web Explorer's local
storage, which can be seen, copied and used in future.
The salt processed jwt token are saved with the username in Mongodb Users Collection, which can be seen and move to another
server (so that we can use the same username and password from
another server to log in and get a new token)
Would anyone like to discuss further about these? Any ideas on how to solve them, and reduce the risk of the website? How about using https?
There is no need to store token in your user schema if you just want to verify your token on other server instances as well. Because, jwt.verify() gives you the functionality to check if the token is valid or not . And if the token valid then you get user info in return which you have used at time of token creation. If you find that user in your database then your token is ok with valid user, otherwise not.
Main thing when creating token is, set expiresIn according to your server demands, so that even if your API security is compromised, it wont be available for long time