Persistence of JWTs in the client browser - javascript

I have a React SPA which makes API calls to a .NET backend. I am currently using JWT authentication. I have implemented the access/refresh token 'pattern'. My problem is that when the page is refreshed, I have to have my tokens stored down somewhere so that, on refresh, the user does not have to log in again to get new tokens. Having spent a fair bit of time researching this issue, it is not clear what the best way of getting around this is.
I have been told that you should not store them down to local storage because they become vulnerable to XSS attacks. A solution which I have come across a few times is to store the tokens in a HTTP-only cookie. Ok - but then I do not see why you don't just use a HTTP-only cookie instead of a refresh token. That is, on log-in, user is issued with relatively long expiry HTTP-only cookie and relatively short expiry access token. On page-refresh, cookie authentication is used to get new access token (if still valid, otherwise user logs in again). I don't mind if, on page refresh, an API call must be made to retrieve a new access token (I just don't want to trigger a user log-in).
I don't understand why a HTTP-only cookie and refresh token might be required, unless it's just to provide another layer of security.

Related

jwt served via httponly cookie with someway to find out is-logged-in

While building a javascript SPA (single page application) I need to display some pages differently based on if the user is logged in or not.
Auth is handled by JWT which is served via httpOnly cookie and secure headers.
That leaves cookie not accessible from the SPA javascript and that in turn means I don't know if the user is logged in or not.
I did check some posts on how to solve this problem and found some suggestions like
send another cookie which is not httpOnly with some flag like session ID or user ID with expiry date and in the client side JS, use that cookie to see if the user is authenticated.
create an endpoint on API server, something like /is-logged-in and make a http call from JS to check if the user is authenticated or not before displaying the page.
store JWT locally without cookies (obviously a no go due to the security reasons and the amount of code I will have to write to mitigate all kinds of possible stealing attacks)
I am late to the SPA party but I am sure this has to be a long solved problem. I am unable to see something obvious I guess.
Please point me to the right direction.
For completeness, here are some unanswered, semi answered related posts
Send a GET request on page load only if user is logged in
How to find out if user is logged in having httpOnly JWT token cookie?
JWT in httpOnly cookie - AuthGuard and protected routes (Node.js, Angular)
http-only cookie + token : double job?
You have basically two choices:
Save that the user is logged in with a second non-http cookie that expires
Pros
No addition HTTP request required
No latency before you know if the user is logged in
Cons
You need to keep the expiration and renewal of both cookies in sync
If your cookies are not in sync anymore because of an edge case, you will need to detect it and act accordingly
Use an HTTP request that will tell you if the user is logged in or not
Pros
Less error prone
No need to change the backend
Cons
You still need to detect if the user is no longer logged in while the user is using the app

Race condition trying to sync access token in multiple tab

Here’s what I’m facing. Currently, refresh tokens are stored in httpOnly cookie, and on every SSR, we refresh the token and send the whole response to the browser, the access token is only saved in memory, then the browser will continue for renewing it. The problem arises when we have 2 tabs, the access tokens will go out of sync. The initial tab’s access token will be unusable.
To work around this, we can either use localStorage to sync the tokens or use non-httpOnly cookie to store the access tokens. Or, manage tokens server-side, But both would have a problem, let’s say Tab 1 sent a request using the current access token, then I open Tab 2, the token is refreshed, Tab 1 request just reached the API, and the token is already invalidated.
I can’t find a proper solution unless we build more server-side logic into NextJS. Or perhaps if we don’t invalidate access token when refreshing and let it dies off the expiry. That way, we have ample time to fight the race condition.
Or, we retry all requests using exponential back off. Actually this kinda solves everything, and there’s a package ready for it. Except we’ll need to rewrite many parts to adopt the new library, and also there would be false alarms in the logs.
Or, we just ignore this and hope the race condition won’t appear, although it seems to me it’s going to occur pretty easily.
We are facing this problem in the company I work for.
Our solution is to store the refresh token in localStorage. If the token is regenerated, the other open tabs would detect a change in localStorage, retrieve the stored token (which now is a brand new one, generated by some other tab) and from that point on use it. The token is stored in memory until another change in localStorage is triggered.
To learn how to detect a change in storage: https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event
Honestly, there is no standard and robust solution to that as far as I know, and based on my research on the Internet.
Interesting problem. In single page apps each tab would be independent and have its own access token that it could store in HTML5 session storage or memory.
In server side web apps cookies are usually shared across all tabs and can cause conflicts.
I would try to follow the SPA model - there is no good reason why using your app on tab 2 should invalidate the token on tab 1.
They are different sessions and should be independent - as they would be if running one tab in Chrome and the other in Firefox.
Keep access tokens short lived (<= 60 minutes) so that after logout on tab 1 the user does not stay logged in on tab 2 for long.

Workflow of login/signup system security for short-lived and persistent authentication

I understand that this question has been beaten to death because I've read a multitude of articles, questions and ideas about cookies and sessions and JWT's and so on. Hopefully this question will not get closed in time to receive some feedback on how I'm trying to handle it.
The articles I settled on are
Charles Miller's article, "Persistent Login Cookie Best Practice,"
"Remember Me" - Long-Term Persistent Authentication
Getting Token Authentication Right in a Stateless Single Page Application
So here's my thinking:
Non-logged in user visits site, basic session is created.
Keep track of user interactions (ex: adding items of interest to cart).
Non-logged in user signs in or signs up.
If session exists, transfer session data as needed.
"selector:validator" as in article 2 is created, selector put into JWT payload, validator into JWT header. "selector:validator" saved in DB.
'persistent' value is added to header as 0 or 1.
If "remember me" checked, JWT expiration set long-lived; if unchecked, JWT exp 15 min.
JWT is signed and split into two parts as in article 3: header and signature are sent as a long-lived secure http-only cookie, payload sent as a readable cookie with extremely short expiration.
The selector and validator should act like the series identifier and token from article 1.
Since this is not an SPA and I'm not using Angular, my thinking to work around the authentication Bearer header is whenever the page loads, get the readable cookie before it expires. On subsequent page navigations, intercept the anchor click, set a cookie with the content from the readable cookie and proceed with that navigation. From my understanding, one major way to prevent CSRF is to set the Bearer header client side, so setting a cookie via Javascript would be the same strategy?
Secured page request on the server, JWT reconstructed and checked whether expired.
If expired and 'persistent' = 0, redirect login.
If expired and 'persistent' = 1, check selector:validator against DB.
If selector and validator the same, issue and update DB with a new validator and sign a new JWT.
If only selector is the same, means cookie was used by another party and that party received a new validator. Invalidate that selector completely and redirect to login.
If none match, redirect to login.
I understand this doesn't address XSS but if XSS is the main issue of the site, everything else goes out the window.
What are the problems with this workflow? Some ways to improve? Or remove altogether for another alternative? I know this is a very broad and general question but I appreciate any feedback so I can stop wrestling with this problem in my head and get back to developing the site. Thank you.
Edit: The reason for going with JWT is have the site somewhat stateless...not requiring a database lookup with every page request. The lookup will only happen every 15 minutes when the JWT will be expired, regardless of persistent login or not. I guess using regular cookies and putting the validator, userId and expiration of 15 minutes into a long-lived, secure http-only cookie would work as well without JWTs...

Is it a secure way to handle returning user in ember?

I am using ember to write a web ui for a site that requires user to log in. Suppose the browser has stored some cookie from last login of a user. Now the user visits the site again. So, is it a secure and common way for ember to log the user in automatically based on the cookie from the last visit? If so, what are the common ways to implement this? (I can't find anything from Google.) Furthermore, how do I create the cookie upon login? Is it a common way to just put a user id, password hash, and expiration in the cookie?
Additionally, any references related to this subject are greatly appreciated.
Edit 1
In light of Vohuman's answer, I think I can make my question a little more specific. Basically, what I want to know is a common and secure implementation to keep a user logged in, even when they close and reopen the browser. Namely, the life time is beyond the session scope. Take linkedin for example. If you are logged in and exit the browser. Then next time you revisit linkedin, you are still logged in automatically. Right now, what I can picture is a solution like the following.
When you first log in to the site, the server will return a cookie which includes an authentication hash token. Then next time when you revisit the site, the server will receive the hash token and thus authenticate your session.
So, is above flow basically what people usually do to keep a user logged in? If so, is the JSON Web Token (JWT) basically one way to construct the hash token I mentioned above? Additionally, assuming the connection is HTTPS, this approach seems secure to me. Is it not?
Edit 2
This article gives an interesting discussion regarding where to store the access token.
is it a secure and common way for ember to log the user in automatically based on the cookie from the last visit?
Yes and no. Security is a complex topic. Usually session cookies are used for authorizing users. This is actually the most used method of keeping the users logged in. If the user can't keep his credentials secure then any layers of security can be vulnerable.
For Single-page applications usually access tokens are used instead of cookies and sessions. The client sends the user credentials and server returns an access token. The token is encrypted and expirable and can be stored in localStorage or sessionStorage. Using JSON Web Tokens (JWT) standard is a popular method for implementing user authentication and authorization in web services. As an example, the Facebook Open Graph API uses access tokens.
JSON Web Token (JWT) is a compact, URL-safe means of representing
claims to be transferred between two parties. The claims in a JWT
are encoded as a JSON object that is used as the payload of a JSON
Web Signature (JWS) structure or as the plaintext of a JSON Web
Encryption (JWE) structure, enabling the claims to be digitally
signed or integrity protected with a Message Authentication Code
(MAC) and/or encrypted.
edit:
So, is above flow basically what people usually do to keep a user logged in?
For traditional websites, yes.
The whole point of using access tokens is keeping the web service/API stateless. This means that server doesn't have to store any cookies/sessions for authenticating and authorizing users. The stateless is one of the key factors of implementing web services that follow the REST paradigm. It's client that has to store the token and send it to the server (via the Authorization header or query parameters). The server doesn't store the token. Of course, you can store the tokens on the server if you want to add another layer of security, but it's not so common and not necessary. Storing the tokens on the server can also make your application vulnerable to database attacks and is not recommended.
If you want to make the process more secure you can decrease the validity time of access tokens (1 hour, 1 day or 1 week, it's up to you).
As for localStorage, is it secure?
localStorage data are stored separately for each origin (domain). A malicious user can only read the data if he/she has access to the user browser. You should make sure that your app doesn't have any XSS vulnerabilities so malicious users can't inject any scripts to your application. This is actually a different topic.

Javascript hashing in AJAX login calls, more security?

From a lot of posts I've seen on the site, logins performed by AJAX or traditional forms are just as secure as one another. (re: Login/session cookies, Ajax and security Ajax login and javascript cookies, is this secure?)
My question(s) is/are:
If I hash the user's password (via client-side/javascript hash
libraries) before I send it to the server, do I increase security from people easedropping?
If I put a form token (one random based, another time based), does that cover CSRF attacks?
Would I have all my bases covered after all this? Would this form be secure?
Actually this could be a major security problem. The reason why passwords are hashed is a means of planning on failure. An attacker might gain access to the data store (sql injection) and then obtain the hash. If you are just logging in with a hash, then the attacker doesn't have to crack the recovered hash in order to gain access to the application.
Replay attacks are also a problem. If I sniff the hash during authentication, whats stopping me from just replaying that request to authenticate?
Protocols that use message digest functions for authentication provide the client with a nonce, which is used as a one time salt. Microsoft's SMB NTLM authentication is a good example, but it has had a lot of problems.
USE SSL, and not just for login. OWASP A9 states that the session id must never be leaked over an insecure channel. After all who cares about the password if you just spill the real authentication credentials a few milliseconds later.
Most people don't implement CSRF protection for login. After all the attacker would have to know the password in the first place, so "session riding" is a moot point.
A slight aside, but in answer to question 3. NO! Also remember that AJAX and standard forms are also just as insecure as one another.
Implementing secure authentication is hard. Unless you are doing it as an academic exercise, i would strongly recommend using the library provided by your framework, if you are lucky enough to have a good one.
You will also need to consider things such as the following, and more.
Implement a suitably random and unguessable session id for use in the session cookie.
Do not allow the session id to be forced.
When permissions or credentials are changed (e.g. because the user has now logged in or out) then
immediately invalidate the session and start a fresh one.
Provide a logout feature, and be sure to invalidate the session upon logout.
Set the cookie to HttpOnly -Preferably require HTTPS and alo set the cookie to secure only.
Consider restricting the session validity to include checking some other information that helps to match the user e.g. user-agent.
Always expire sessions after non-use and do not implement "keep me logged in" by reconnecting the user to their old http session.
Ensure 2 sessions can't have the same session id at the same time
Ensure that all session data is destroyed when a session is invalidated. A new user coming along, may just happen to get assigned a session id that has been used previously. This new session must not have any access to session data that has been set previously against that session id.
If the attacker knows what hashing you are using then they can crack it. And if you want to add a salt you have to send it to the browser and the attacker could intercept it. Using the time as a salt also won't work because there is only a relatively short amount of time so they can solve that as well.

Categories

Resources