We know if the JWT content is modified, the server simply finds it using the signature. But what if the JWT is stolen and used by a hacker without modifying it? How the server verifies the JWT comes from the correct client?
I know the user id is inside the JWT, but still I am not sure how the server can securely makes sure the JWT comes from the client who is having the same user id that is in the JWT.
A hacker can't and won't modify the token. As the token itself is safe and is fully trusted. This is the nature of a JWT. So without additional information you can't tell the difference.
You can however design a strategy to protect your resource.
Most important is to prevent a hacker from 'stealing' the token. It helps when you send the token always over a secured line and store information (like tokens) in a secured place.
Make it not worthwhile to hack the token. Use short-lived tokens, like five minutes or less. When a hacker gets hold of a token it will only give access for a short period. This is the 'acceptable loss'. On the other hand the hacker is discouraged as the effort is not worth the result.
Detect suspicious behaviour. Like hundred hits per second or varying ip addresses with the same token.
When using a refresh token, check the requesting party. Is the Ip address within range? Use one-time only refresh tokens. Only allow refresh tokens when the client can keep a secret. Use expiration on refresh tokens, this will force the user to login every now and then.
And add additional information to the claims in the token. Like the ip address, used agent, etc. These are quick checks.
When the ip address is not the same as in the claim, do not accept the token. The app will need to send a refresh token to obtain a new access token. The hacker can't do this without a refresh token.
Keep track of succesful login ip addresses. For a known ip address the token can be refreshed. For an unkown ip address (a possible hacker, or unknown changed wifi network), invalidate the refresh token. That way the user is forced to login again.
As an additional security measure contact the user (send an e-mail like Google does) when there was something different. In that case the user can revoke the refresh token.
Related
So here is the modification of jwt access-refresh authorization schema without addressing database I come up with:
We store ip-address and device type in jwt refresh token, then encrypt the token.
Let's imagine malicious user hijacks the refresh token. The malicious user doesn't know anything about content of such refresh token as it is some encrypted string.
He wants to receive a new refresh token and sends us the hijacked one.
We decrypt the token, extract ip-address and device type from the token and compare with ip-address and device type of request. If they were equal, then we know it is request from authorized user and we give him new refresh token, otherwise it is request from malicious user and we reject the request.
Is there any pitfalls with such authorization schema?
Encrypting the refresh token is a good idea. It is a way of changing the JWT token into an opaque one, without the need for a database. It's also convenient that the token will be decrypted only by the authorization server, so there is no need to distribute any keys.
As for rejecting tokens with a different IP — that actually depends on your system and the characteristics of your users. A user's IP number can change even when it's not a malicious action. E.g., the user might switch to a different wifi or turn on VPN protection and will get a new IP number. Many routers are also assigned a new IP on every connection to the ISP, so the IP number can sometimes change even when the user does not change their location or network settings. If you know that this will not happen to your users and that they should always operate under the IP that they logged in from (maybe you have a system that is only meant for employees connecting from a concrete VPN), then that approach might be ok.
You would also need mechanisms in place that will protect against spoofing IP information. The same goes for the device type. You would have to make sure that you have a reliable source of information for the type of device, and that that information cannot be spoofed.
I'm learning purpose of JWT tokens in ASP.NET Core, but I don't understand one thing. Why does every blog calling JWT authentication? If we pass a token to an authenticated (logged-in) user. I mean why JWT is not authorization but authentication? Can't understand which point I'm skipping in this topic.
In a typical implementation, the JWT token that you create for a signed in user will be sent with every subsequent request. The purpose is that you want to make sure that the party that sends the request is actually who they are claiming to be - ie. you want to authenticate requests.
Strictly speaking, without this, you could not do authorization, or well, you could, but it wouldn't make much sense if you just beleived who the caller was instead of checking (authenticating).
Edit:
The jwt token will always have a "sub" field, a subject, usually a user identifier, and an expiry, even if there are no further claims. The token is also signed(*) that can and must be verified. So if somebody can present a token with their identifier, signed by your server, with a timetstamp not very long ago, then you can be sure that they recently authenticated, eg. provided their password. In all subsequent requests you don't need to get their password, you only check the token. You know they are who they say to be, because they have a valid token, your server signed their email address, so they are logged in.
An attacker cannot forge such a token, because while they can replace or forge their user identifier (the sub field), the signature on the token will not be valid. Only your server can make a signature that can then be verified (by your server in this case).
So in other words, there is the initial user authentication, when they provide their username and password, but HTTP is basically stateless, the next HTTP query has nothing to do with the first one. You explicitly have to make this connection, ie. create a user session, you have to securely "remember" that when a new request comes in from a user, it's the same user that already provided their password. So when they do provide their password, you make a JWT for them with their email address and a timestamp, sign it, and next time they only send that, and you know it's them, because there's you signatuare on the token.
The reason you don't want them to send their password all the time is that sending passwords around in every request would present a somewhat higher risk, but much more importantly, then the client app (the browser in a webapp) would have to remember a user's password, which is not good, it's by far more secure to erase that from the browser's memory. So you create them a JWT instead.
Also note that in such a usecase, a JWT is unnecessary, maybe that's where your confusion comes from. You could just send the user a plain old random session token, which you also store on the server, and store all state in the server-side session. This is all fine, and actually more secure than a JWT. JWTs should be used for example when the authentication token needs to be sent to different origins (domains), or when secure claims should be shared with another party. Using JWTs for primary authentication with a simple web app with one origin is unnecessary (very fancy today, but not correct).
(*Note that for such a usecase, the signature is usually a message authentication code, a MAC, but I did not want to confuse you further with this word, as message authentication is another authentication. You can just think of this as a signature for now, though signature in cryptography is something different, and even more confusingly, JWTs can use actual signatures too.)
Nowadays many developers use the JWT Authentication to authorize the api call.
By the way, if a hacker can capture the api call request of the authenticated user then he can have the authenticated JWT token.
Then the hacker can access this api with the authorized JWT token, without his authenticating.
Is this alright?
I am wondering that the JWT Authentication is actually safe.
Can you explain that?
A jwt is a code that contains information about the identity and claims of a user and is valid for only a limited amount of time.
The code cannot be read nor changed by anyone, except the authorization endpoint that issued the token. It is therefor safe in the sense that it cannot be tampered with. This means that the token can be fully trusted. You don't have to validate the token and you can use the identity information and claims without having to consult the database.
But this is also the disadvantage. Once issued the token is valid until it expires, since the expiration cannot be altered. That is why the token should only be send over a secured line to the server. You wouldn't want a hacker to intercept the token.
But if it happens, then what?
There are several options. You can use short-lived tokens, which means that a token expires short time after being issued. If a token was intercepted, it is only valid for a small amount of time. In that case you take for granted that a hacker can have access for limited time to the system. The advantage is that you need less resources and the effort of hacking is probably not worthwhile.
Another option is to validate the token on each request. This requires more resources (e.g. lookups in the database), though you can use some sort of caching. If something changes, like the ip address, then you can invalidate the token. But the question is if you can detect if a token was send by a hacker.
So it depends on the chosen strategy. But: if you issue a long-lived access token without validation (and thus without the possibility to revoke the token), then you'll have a problem if a hacker gets hold of an access token. So you'll need to do something to use it in a safe way.
While I think this should be enough to help you understand, I would like to mention the use of refresh tokens. If you use short-lived access tokens, then you may want to implement long-lived refresh tokens. These refresh tokens are meant to obtain a new access token after it expires. The advantage is that you don't need to send the credentials, the refesh token suffices. You can however only implement this in an application that can keep a secret. Because you most certainly do not want a hacker to intercept the (long-lived) refresh token.
Being used less frequently (opposed to the access token) you can add logic to validate the refresh token when used. You can consult the database and decide to reject the request (e.g. when ip address changed) and revoke the refresh token. In that case the user has to identify itself again (send credentials).
JWT is just a secure msg transporter between fsb server and client so that fsb server can determine whether the client is logged in or not; if logged in, the fsb server will fetch personal unique user based data.
google oauth
G sends back user gid to my server only if user has a google account and successfully inputs gmail and password correctly.
user id is saved in jwt’s payload.
jwt
if google validates the user and google returns gid
create jwt content and internal maintenance: exp date, encryption
jwt is sent and stored in local store of user’s browser;
each user’s req sends jwt back to my server
my server decodes the jwt using secretOrKey, which only my server has, and gets the content(uid) from the jwt.
if uid is in my db, user had already registered and right now is logged in.
send the requested data from my db to the user because he is logged in
if use fails google validation due to wrong password or G email, jwt isn't created.
Process of JWT
user’s google popup logs in
google server returns information to my server. If the gid isn’t in my db, I’ll save it in my db so that the user can be registered.
create jwt and add uid as content. Exp date.
jwt is sent and stored in local storage of users browser
user requests a page though http, it includes the jwt. my server checks whether this user is logged in or not by Login determination test: if user’s jwt uid is in my DB, user is logged in. the user requested data will be given to the user. If user doesn’t have jwt or uid doesn’t match then the user isn't logged in, send the user to login page.
JWT descriptions
https://medium.com/#rahulgolwalkar/pros-and-cons-in-using-jwt-json-web-tokens-196ac6d41fb4
https://scotch.io/tutorials/the-ins-and-outs-of-token-based-authentication
https://scotch.io/tutorials/the-anatomy-of-a-json-web-token
https://auth0.com/blog/cookies-vs-tokens-definitive-guide/
I'm working on a cloud service authentication system and I'm not entirely sure what the optimal way to handle authenticating requests is. We're planning to run our image server as a separate process from our API server so that we can scale them independently of each other. Handling request authentication with API keys is fairly simple, because we can just have the image server store its own API key and check that requests provide it in a header (over HTTPS obviously), same with the API server. For users though it gets more complex.
Right now we have it setup so that the API server will handle generating a session token and storing users in its database, however what we'd like to do is use 3 servers:
authentication server
API server
image server
and have the image and API servers authenticate requests against the authentication server. How exactly should this be done though? It seems like a bad idea performance-wise to hit the authentication server for every request that the API and image servers make. Can/should a token be verified from a different server than it was created on?
So for example: can/should I pass the token received from the authentication server to the image server, verify that the token came from "my.auth.server" and check that the user ID is the right one? Would JWTs be a good type of token for this?
Here's an alternative approach.
Your authentication issues a JWT token that is signed using a secret that is also available in your API and server images. The reason they need to be there too is that you will need to verify the tokens received to make sure you created them. The nice thing about JWTs is that their payload can hold claims as to what the user is authorised to access should different users have different access control levels.
That architecture renders authentication stateless: No need to store any tokens in a database unless you would like to handle token blacklisting (think banning users). Being stateless is crucial if you ever need to scale. That also frees up your API and image servers from having to call the authentication server at all as all the information they need for both authentication and authorisation are in the issued token.
Flow (no refresh tokens):
User authenticates with the authentication server (eg: POST /auth/login) and receives a JWT token generated and signed by the auth server.
User uses that token to talk to your API and image servers and assuming user is authorised), gets and posts the necessary resources.
There are a couple of issues here. Namely, that auth token in the wrong hands provides unlimited access to a malicious user to pretend they are the affected user and call your APIs indefinitely. To handle that, tokens have an expiry date and clients are forced to request new tokens whenever expiry happens. That expiry is part of the token's payload. But if tokens are short-lived, do we require users to authenticate with their usernames and password every time? No. We do not want to ask a user for their password every 30min to an hour, and we do not want to persist that password anywhere in the client. To get around that issue, we introduce the concept of refresh tokens. They are longer lived tokens that serve one purpose: act as a user's password, authenticate them to get a new token. Downside is that with this architecture your authentication server needs to persist these refresh token in a database to make them revokable before they expire (think "revoked" column in tokens table).
New flow (with refresh tokens):
User authenticates with the authentication server (eg: POST /auth/login) and receives a JWT token generated and signed by the auth server, alongside a long lived (eg: 6 months) refresh token that they store securely
Whenever the user needs to make an API request, the token's expiry is checked. Assuming it has not yet expired, user uses that token to talk to your API and image servers and assuming user is authorised), gets and posts the necessary resources.
If the token has indeed expired, there is a need to refresh your token, user calls authentication server (EG: POST / auth/token) and passes the securely stored refresh token. Response is a new access token issued.
Use that new token to talk to your API image servers.
OPTIONAL (banning users)
How do we ban users? Using that model there is no easy way to do so. Enhancement: Every persisted refresh token includes a blacklisted field and only issue new tokens if the refresh token isn't black listed.
Things to consider:
You may want to rotate refresh token. To do so, blacklist the refresh token each time your user needs a new access token. That way refresh tokens can only be used once. Downside you will end up with a lot more refresh tokens but that can easily be solved with a job that clears blacklisted refresh tokens (eg: once a day)
You may want to consider setting a maximum number of allowed refresh tokens issued per user (say 10 or 20) as you issue a new one every time they login (with username and password). This number depends on your flow, how many clients a user may use (web, mobile, etc) and other factors.
You can store some additional metadata (ip, geolocation, device, browser cookie, etc.) alongside refresh tokens. That way, you can be smart about when to reject malicious usages of refresh tokens in case it's compromised.
Common Q: Why store all refresh tokens, and not just revoked ones? You could do that. Ask yourself the following: Will I, at any point, need to have a functionality where I can dynamically revoke valid refresh tokens, based on some arbitrary, regulatory, legal, integrity, security etc. criteria? If so, the least you will need is a list of all issued tokens, plus any data required to implement the criterion logic. Example: Due to regulation, I need to ban all EU users equates to a delete from refresh_tokens were user_ip in <... eu logic ...>
one of the best ways to use is a JWT Token , you can generate and share it between all your servers and validate it on the server side .
https://jwt.io
also I think the best architecture to use in this case is the micro service architecture
I am trying to implement stateless authentication with JWT for my RESTful APIs.
AFAIK, JWT is basically an encrypted string passed as HTTP headers during a REST call.
But what if there's an eavesdropper who see the request and steals the token? Then he will be able to fake request with my identity?
Actually, this concern applies to all token-based authentication.
How to prevent that? A secure channel like HTTPS?
I'm the author of a node library that handles authentication in quite some depth, express-stormpath, so I'll chime in with some information here.
First off, JWTs are typically NOT encrypted. While there is a way to encrypt JWTs (see: JWEs), this is not very common in practice for many reasons.
Next up, any form of authentication (using JWTs or not), is subject to MitM attacks (man-in-the-middle) attacks. These attacks happen when an attacker can VIEW YOUR NETWORK traffic as you make requests over the internet. This is what your ISP can see, the NSA, etc.
This is what SSL helps prevent against: by encrypting your NETWORK traffic from your computer -> some server when authenticating, a third party who is monitoring your network traffic can NOT see your tokens, passwords, or anything like that unless they're somehow able to get a copy of the server's private SSL key (unlikely). This is the reason SSL is MANDATORY for all forms of authentication.
Let's say, however, that someone is able to exploit your SSL and is able to view your token: the answer to your question is that YES, the attacker will be able to use that token to impersonate you and make requests to your server.
Now, this is where protocols come in.
JWTs are just one standard for an authentication token. They can be used for pretty much anything. The reason JWTs are sort of cool is that you can embed extra information in them, and you can validate that nobody has messed with it (signing).
HOWEVER, JWTs themselves have nothing to do with 'security'. For all intents and purposes, JWTs are more or less the same thing as API keys: just random strings that you use to authenticate against some server somewhere.
What makes your question more interesting is the protocol being used (most likely OAuth2).
The way OAuth2 works is that it was designed to give clients TEMPORARY tokens (like JWTs!) for authentication for a SHORT PERIOD OF TIME ONLY!
The idea is that if your token gets stolen, the attacker can only use it for a short period of time.
With OAuth2, you have to re-authenticate yourself with the server every so often by supplying your username/password OR API credentials and then getting a token back in exchange.
Because this process happens every now and then, your tokens will frequently change, making it harder for attackers to constantly impersonate you without going through great trouble.
Hopefully this helps ^^
I know this is an old question but I think I can drop my $0.50 here, probably someone can improve or provide an argument to totally decline my approach.
I'm using JWTs in a RESTful API over HTTPS (ofc).
For this to work, you should always issue short-lived tokens (depends on most cases, in my app I'm actually setting the exp claim to 30 minutes, and ttl to 3 days, so you can refresh this token as long as its ttl is still valid and the token has not been blacklisted)
For the authentication service, in order to invalidate tokens, I like to use an in-memory cache layer (redis in my case) as a JWT blacklist/ban-list in front, depending on some criterias:
(I know it breaks the RESTful philosophy, but the stored documents are really short-lived, as I blacklist for their remaining time-to-live -ttl claim-)
Note: blacklisted tokens can't be automatically refreshed
If user.password or user.email has been updated (requires password confirmation), auth service returns a refreshed token and invalidates (blacklist) previous one(s), so if your client detects that user's identity has been compromised somehow, you can ask that user to change its password.
If you don't want to use the blacklist for it, you can (but I don't encourage you to) validate the iat (issued at) claim against user.updated_at field (if jwt.iat < user.updated_at then JWT is not valid).
User deliberately logged out.
Finally you validate the token normally as everybody does.
Note 2: instead of using the token itself (which is really long) as the cache's key, I suggest generating and using a UUID token for the jti claim. Which is good and I think (not sure since it just came up in my mind) you can use this same UUID as the CSRF token as well, by returning a secure / non-http-only cookie with it and properly implementing the X-XSRF-TOKEN header using js. This way you avoid the computing work of creating yet another token for CSRF checks.
Sorry being a little late on this, but had the similar concerns and now want to contribute something on the same.
1) rdegges added an excellent point, that JWT has nothing to do with the "security" and simply validates, if anyone has messed up with the payload or not(signing); ssl helps to prevent against breaches.
2) Now, if ssl is also somehow compromised, any eavesdropper can steal our bearer token (JWT) and impersonate the genuine user, a next level step what can be done is, to seek the "proof of possession" of JWT from the client.
3) Now, with this approach, presenter of the JWT possess a particular Proof-Of-Possession(POP) key, which the recipient can cryptographically confirm whether the request is from the same authentic user or not.
I referred Proof of Possesion article for this and am convinced with the apporach.
I will be delighted, if able to contribute anything.
Cheers (y)
To deal with the problem that tokens are getting stolen, you map each JWT with the list of valid IPs.
For eg, when the user logs in with a particular IP when you can add that IP as valid IP for that JWT, and when you get the request pf this JWT from another IP (either the user changed the internet or JWT is stolen, or any reason) you can do the following depending on you use case:
Map CSRF token with user token and incase it gets stolen then it's CSRF token will not match in that you can invalidate that user token.
You can provide a captcha to the user to validate if he is a valid user or not. If he enters the captcha then add that IP to the valid list of that JWT.
You can log out the user and make a new request to log in again.
You can alert the user that your IP has changed or requested from a different location.
You can also use cache with a small expiry of 5 mins in above use-cases instead of checking each and every time.
Suggest if it can be improved.
Can't we just add the ip of the initial host which has requested to generate this JWT token as part of the claim ? Now when the JWT is stolen and used from a different machine, when the server validates this token, we could verify if the requested machine ip matches with the one set as part of the claim. This would not match and hence the token can be rejected. Also if the user tries manipulate the token by setting his own ip to the token, the token would be rejected as the token is altered.
Once the token gets stolen - it is game over.
However there is a way to make it harder to make use of a stolen token.
Check https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html#token-sidejacking for reference.
Basically, you create a x-Byte long fingerprint in hexadezimal, store its raw value in the token - hash the fingerprint using for example SHA-512 and put the hashed fingerprint inside a httponly secure cookie.
Now instead of validating just the signature and expired date of the token you need to also validate the existence of the cookie and be sure that the raw fingerprint values match.
Client should use part of the hash of user password to encrypt the time that the http msg was sent by client to the server. This part of the hash should also be encrypted with some server secret key into the token when it is created.
The server than can decrypt the http request time and verify for short time delay.
The token is going to change every request.