Is this an acceptable approach to refreshing JWTs? - security

I'm in the process of rebuilding an existing web app, that uses JWTs to manage authentication. I'm still new to JWTs, so I'm learning about how they should work, while, at the same time, trying to understand why the web app's current implementation is the way it is.
The current version's flow is as follows:
When a user successfully logs in or registers, a user object is returned along with a JWT property. This JWT is included in subsequent API calls as an Authorization header.
Every ten minutes, a get request is made to API endpoint /refresh-token.
If successful, the response body contains a success message, and the response header contains an updated Authorization header.
All subsequent ten-minute timed get requests to /refresh-token use the original JWT that was returned in step 1, and so on.
From what I've read so far, this doesn't correlate with any recommended approaches.
Is it safe enough to replicate this flow in the newer version, or is this something I'm better off not replicating?
Edit: I'm working solely on the front-end - the API isn't being updated for a while, so I'm limited to what it currently returns.

I believe this article summarizes the current state of the art: https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/. You usually have two tokens. Access token which is short lived and an refresh token, which lives longer. This way you don't need to call the auth server every x minutes, but you can do it on demand.
I don't know if you need to deal with blacklisting too? I believe blacklisting is easier when you have a separation of access token and refresh token (only refresh token needs to be blacklisted). But I believe you could deal with this problem too, probably in a bit more sophisticated manner.
Having said that. What you have is not wrong. It's hard for me to point out any flaws in the way you are doing besides of what has been pointed out above.

Related

JWT - What is the best way to use jsonwebtoken ? I'm lost

I’m learning to code for one year now. I mainly learned how to deal with a rest API (Node/Express on back-end and Vue on front-end).
I get to the point where I want to develop the ideas I have for app.
For this, I first wanted to develop the backend to have a authentification process that I could use as a boilerplate for other project I would have.
But now I’m completely lost with Jsonwebtoken and how to exactly use it in order to make something secure as well as user-friendly.
So far I understand that a rest API should be stateless (I.e. nothing should be store server-side and should therefore not have DB calls -as for sessions- to grant access to data).
In this respect, I’ve noted different strategies :
Short-lived JWT : (+) this is very secure since you theoretically have to log in every time you want to access the server (-) very bad user experience
Long-lived JWT : (+) user-friendly (persistent login) (-) very insecure (no way to check if JWT was stolen)
Short-lived JWT with Long-lived Refresh Token…
That’s where I get confused…
From every articles/tutorials I’ve read, the refresh token should be linked somehow with a DB (e.g. to store the refresh token key or the blacklisted token…). I’ve also seen a tutorial that partly linked the secret key (to verify the token) with the hashed password stored in the DB. This is kind of smart since previous token will automatically be considered as invalid as of the moment the user changes his password… But this once again mean a DB call…
My point is that I’m coming to the conclusion that
(1) there’s no perfect way to handle authentification process in secure and user-friendly way…
(2) DB calls cannot be avoided to have something a bit secure...
And considering that conclusion, I definitely can’t understand the use of refresh token…
If refresh tokens required DB calls, you could get to the same result with only one main token…
You could for instance store a JWT ID in the token and in the DB… If those two id match upon validation of the token, you issue a new token with a new id that overwrites the previous one… Now if you use an old one, it will never be validated… Then, since you have called the DB to validate the token (most certainly the USER table), you could check in the sametime if, for example, the user is an admin or not (no need to store it in the JWT)… Finally, you could use the « hashed password » trick described above to enhance security…
So… What am I missing ? What is the best strategy ?
I’ll be happy to have your comments on this (or a link to a very good article - I’ve a lot of these though…)
Thank you very much for your help
PS: and I’m not even talking about how to send the token to the server (with cookie but risk of CSRF attach or with header but subject to XSS attack if token is stored client-side)… In this respect I’ve seen multiple tutorial that use JWT through cookie with cerf key stored client side as well as inside the jet => both should be send.
PS2: I hope I'm clear since I'm french-speaking native :-)
So you have asked quite a few questions in this one question. It will be quite difficult for anyone to give a thoughtful answer here, but I shall try. Before that, full disclaimer, that I am the author of a new library called SuperTokens that I believe would provide you the best solution for session management. It's possible that you may have already read our blog: https://hackernoon.com/all-you-need-to-know-about-user-session-security-ee5245e6bdad. It's best if we can chat about this so that I can give you a full detailed explanation about everything you have asked (I would love to help out). Join our discord: https://discord.gg/zVcVeev
Now to answer your question(s):
You should always only use short lived JWTs
Doing a database call for authentication is not a problem, but as everything else, we try and optimise things, so doing fewer db calls, is better. If you go with JWT access tokens and Opaque Refresh tokens, then for most APIs, you do not need to do a db call. However, if you link the secret key of the JWT with the hashed password, then you would have to a db call for every API - which is OK, but I feel unnecessary since you are going to use short lived JWTs anyways (a few hours to a day max)
You mentioned token theft - this is a tricky issue, but according to RFC 6819, you can use the concept of rotating refresh token to detect theft. Of course, actually doing so can be tricky as you have to take care of many race conditions and network failure issues - see https://hackernoon.com/the-best-way-to-securely-manage-user-sessions-91f27eeef460
About why we need refresh tokens: Say you do not have a refresh token, then you would have just one token that you could treat as both, an access and a refresh token. You could still make it short lived (when it's an access token), and then after it expires, treat it as a refresh token - which also has some lifetime. The problem with this is that it's not very clean (point of expiring a token is that it is useless afterwards), and that you are exposing the refresh token over the network every single API call - reducing security. I know you can have HTTPS, but there are HTTPS MITM attacks as well - see the blog post, part 1.
In terms of storage, one neat trick could be to split the access token into two - one to store in secure, httponly cookie, and one to store in localstorage. For every API call, send both to the server (cookies will be sent automatically anyways), and then the server would combine the two and go about authenticating. This would prevent both, CSRF and XSS attacks on sessions!
Now, you could either implement this whole thing on your own, or then use our library that does all these things out of the box: https://github.com/supertokens/supertokens-node-mysql-ref-jwt.
To discuss this more, or any other questions you have, join our discord server.
PS: I know I used this for advertising my lib, but I hope I did answer your question. It is genuinely difficult to give a good explanation to your questions without having a conversation.

Is there a way to protect an API route from being hit by an authenticated user outside of an app making requests?

I'm making an angular app that has users log in, make progress, then they are awarded levels/experience points. I'm using a nodejs/express API and I want to be able to make a call from my app to award them exp. I'm using a JWT and server signing with a private key to auth requests, but realized that a user could just pull their token and give themselves experience. My question would be is there anyway to protect my route from that or is that a fundamental flaw in design?
I don't believe this is something you can do specifically with JWT. As commenters have already said, JWT just provides access rights for the given token. As you say yourself, it would be simple enough to just read the traffic and send their own requests to jack up their exp.
While your basic authentication/authorisation mechanism can't solve this, you can handle it in some other fashion within, for example, the request payload itself.
You could encrypt and/or sign your payloads - given that the app would need to know or receive key(s) to use, it's possible that with enough investigation that this is eventually found and duplicated as well. But it's another step someone would have to go through and replicate.
You could employ additional checks and measures - have your requests for [exp increase] be a two-step process; the server responds to the initial request with some minor task to be solved that is then attached to the follow-up request. Assuming the task is done properly, you can be reasonably sure that it came from your app as your app knows how to solve the problems issued (or someone with a serious lack of hobbies outside of deconstructing your entire application).
You could limit the amount of exp that should be reasonably achievable by your users. If you know that people should, at most, be able to gain xyz exp per minute/hour/day/etc, then by monitoring exp growth, you can flag and/or block additional gains past this point.

Remember Me Token in Nodejs RESTFul API

I'm developing a RestFul Apis for a mobile application (Android App). I'm using 2-Step auth using OTP and remember me token. For the remember me token I'm currently using Remember Me (any other similar strategy npm is welcome). The npm basically sets a unique token to a cookie which the App can use to verify itself. According to documentation in the above NPM, it recommended to re-generate the tokens after every request.
However in the event when the mobile App makes multiple parallel requests, all the parallel request use the same token. This undoubted give an auth error. I guess this is common situation. I wanted to know if there is a standard way to handle this ?
Current Workflow
Mobile App request authentication with a given OTP
Upon successful verification, the App is give a token which is
passed back in a cookie
For calls to protected APIs, the App calls
the API with cookie passed back in the previous step.
The server resets the token in the cookie and sends back the response to the App
Issue with the workflow
The App is successfully logged-in and has a valid cookie.
App makes a call to a protected API /protected_api_1
The server has reset the token in the cookie for the above call but has not yet completed the reponse
App makes a second call /protected_api_2, with the old cookies as the App does not have the new cookie with it.
Auth fails for (3)
Ok, checking your update I think of 3 workarounds for this. Let's say we have 3 actions, (a), (b) and (c) that requires the token to consume the API.
Token Store
With this just I mean a class, file, cookie or object where you can save your current token, and you can update with the new token after an action is completed.
The problem with this solution is that if you make (a), (b) and (c) at the same time with the same token, the first one who finishes would update the store, and the other 2 would fail. You would have run them synchronously or concurrently.
If you want to do it this way, maybe it would be a better idea to have a:
Lock: a boolean variable that indicates that the token is being used and that the current request must wait for the token to execute and update the token.
Queue: just a linked list where you push the requests and they are consumed asynchronously when the lock isn't set. You implement a service in another thread that handles the queue, may in a similar fashion to a reactor pattern.
Grouping The Requests
Let's suppose that your application executes (a), (b) and (c) very often. In that case, it would be a good idea to group them in just one action and execute it on the server with just one callback. This could be complicated in your case because it would require to create new resources or think about your modeling of the problem.
Managing token expiration
I've seen this in some projects. You set a soft expiration for the token, let's say 15 minutes (or even less). After the time has passed, you give the client a new token, before that time you keep the same token. (a), (b) and (c) would run at the same time with the same token. Problems would happen when you run the requests near the expiration time, depending on how long it takes to complete them.
I can't give you more details about implementation because I don't know in what language or framework you are implementing the client, and I've never made an Android Application, but I think it would be a good idea to try one of this ideas or a mix of them. Best wishes.
Original
I don't understand what do you mean by parallel in this context.
Try making a Token Store resource in your app which every parallel request consumes and updates after request is done.
If all requests are sent at the send time, maybe it would be a good idea to group them in just one operation, but that would maybe require API endpoint changes.

Why does Express/Connect generate new CSRF token on each request?

As far as I understand there are two approaches in protecting from CSRF attacks: 1) token per session, and 2) token per request
1) In the first case CSRF token is being generated only once when the user's session is initialized. So there is only one valid token for the user at once.
2) In the second case new CSRF token is being generated on each request and after that an old one becomes invalid.
It makes harder to exploit the vunerability because even if attacker steals a token (via XSS) it expires when the user goes to the next page.
But on the other hand this approach makes webapp less usable. Here is a good quotation from security.stackexchange.com:
For example if they hit the 'back' button and submit the form with new values, the submission will fail, and likely greet them with some hostile error message. If they try to open a resource in a second tab, they'll find the session randomly breaks in one or both tabs
When analizing Node.js Express framework (which is based on Connect) I noticed that a new CSRF token is generated on each request,
but an old one doesn't become invalid.
My question is: what is the reason to provide new CSRF token on each request and not to make invalid an old one?
Why not just generate a single token per session?
Thank you and sorry for my English!
CSRF tokens are nonces. They are supposed to be used only once (or safely after a long time). They are used to identify and authorize requests. Let us consider the two approaches to prevent CSRF:
Single token fixed per session: The drawback with this is that the client can pass its token to others. This may not be due to sniffing or man-in-the-middle or some security lapse. This is betrayal on user's part. Multiple clients can use the same token. Sadly nothing can be done about it.
Dynamic token: token is updated every time any interaction happens between server and client or whenever timeout occurs. It prevents use of older tokens and simultaneous use from multiple clients.
The drawback of the dynamic token is that it restricts going back and continuing from there. In some cases it could be desirable, like if implementing shopping cart, reload is must to check if in stock. CSRF will prevent resending the sent form or repeat buy/sell.
A fine-grained control would be better. For the scenario you mention you can do without CSRF validation. Then don't use CSRF for that particular page. In other words handle the CSRF (or its exceptions) per route.
Update
I can only think of two reasons why single dynamic token is better than multiple:
Multiple tokens are indeed better but have at least one dynamic token like one above. This means designing a detailed workflow which may become complex. For example see here :
https://developers.google.com/accounts/docs/OAuth2
https://dev.twitter.com/docs/auth/implementing-sign-twitter
https://developers.facebook.com/docs/facebook-login/access-tokens/
These are tokens to access their API (form submission etc.) not just login. Each one implements them differently. Not worth doing unless have good use case. Your webpages will use it heavily. Not to mention form submission is not simple now.
Dynamic single token is the easiest, and the readily available in library. So can use it on the go.
Advantages of multiple tokens:
Can implement transactions. You can have ordering between requests.
Can fallback from timeout and authentication errors (you must handle them now).
Secure! More robust than single tokens. Can detect token misuse, blacklist user.
By the way if you want to use multiple tokens you have OAuth2 libraries now.

See any security risks with this approach?

I'm working on a RESTful(ish) API that has the following authentication style:
A client calls an "authenticate" API method and passes a username and password over HTTPS POST. This method returns basic account information and a "client token", which is stored on the user account in the database.
All further API calls (all over HTTPS POST) require a client token. If the system can't find the requester by client token, the call is rejected.
My open questions are:
1) Does anyone see a major security problem with this?
2) Is there any good reason why I should have client tokens expire over time or change? Right now I assign a random one to every user. If the user does a logout or forgot password, I generate a new one.
I'd love to know everyone's thoughts on this approach. I'm not going for innovation, I'm just making I'm aware of the risks on this approach.
What you've described is functionally equivalent to a session cookie, only reimplemented in your application, and therefore subject to a number of pitfalls that have likely already been dealt with by most web frameworks.
Ensure your tokens have enough bits of entropy. If the tokens are simple 32-bit integers, wild guesses might be enough to hit on one in use by someone else.
If you're generating these tokens randomly, ensure you use a cryptographically-strong source of random numbers, or the next token might be guessable based on previous tokens.
If these POST requests are coming from scripts and such embedded in web pages, passing the token around as an explicit parameter instead of as a cookie declared secure and httponly makes token-stealing by cross-site scripts much easier.

Resources