Most examples always take into consideration only one users using the system in the JWT/Flask tutorials. I want to understand this at a multi-user level but cannot find the correct resources.
Lets say we have the following secret key:
app.config['SECRET_KEY'] = 'randomkey'
Two Questions:
Would this key be the same for every user? if so, wouldn't this provide a security risk because if the key was stolen, anyone would have access to do whatever they want?
If it is not the same, how is the key stored on the server-side so it could be authenticated when requesting information? Would it be stored within the user's table under current token or something?
In this case, that key is the JWT signing key It could also be different from flask's secret key setting (see flask docs). It's not used for encryption so it's not intended to be a shared secret between server and users. Its role is to provide the server with a proof that the JWT content was generated by the server itself: it's a proof of integrity.
Having knowledge of that key means having the right to issue JWTs on behalf of the application, attackers could impersonate servers or make requests with some modified claims, eg pretending to be other users. This means that these keys are quite sensible from security perspective
Turns out that 1 app : 1 key, with some remarks
This key should theorically never change: if at time T1 KEY=x, a user could login in and receive a JWT signed with KEY=x. at T2 KEY=y, the user will invoke some API using the previous JWT and the server will try to verify(signature(payload , x) , y). So every user will be logged out automatically
Despite 1. It would be good to rotate the key. In this case the authentication system should save a buffer of old keys and use them to validate oldest JWT. Since a JWT should be short-lived, it could be useful set a rotation time grater than JWT expire time and just keep the last used key along with the current
This key is a secret and should be managed exactly as other secrets. Aside from terrible approaches like leaving it plaintext in the code/config, there are secret managers from cloud providers, or kubernetes secrets if you use the latter, as well as secret managers from configuration management tools (salt, ansible) or Hashicorp's Vault that is a specialized storage engine for sensible data. Anyway, it's more infra/security team concern if you are in a structured organization
Related
So my question is about asymmetrically signed JWT tokens. How is it ensured that the signature can't be replicated on JWT tokens? If someone captures the JWT, what prevents him from reusing the same JWT over and over again without being properly authorized? I believe JWTs can have an expiration date, but it doesn't solve the issue since expiration date for most apps are relatively long in order to provide a good user experience. Most simplistic but a naive solution I can think of is having a nonce attached to the user starting from 0 and incrementing every time the jwt is used, and the request is processed.
Preventing replication of the signature of the JWT relies on you storing the key correctly that signed the JWT, either in a secure storage or some other safe place, reuse is a different story.
Now, for a start, I would also be worried if an attacker can easily steal your JWT, which almost implies that you don't use HTTPS/SSL, but sure, let's assume we are running a scenario where someone has exploited your SSL.
JWT's themselves are nothing more than ways of authentication a client, almost similar to how an API key works. It's pretty much a grant that that client can access some resource using that token. It doesn't hold any security value in that regard, other than at some point that client authenticated itself using the correct credentials.
So if it's stolen, you have a problem. This is where the lifetime of the tokens comes in to play. Tokens can expire very quickly, causing the attacker to only be able to access resources for a short while, but still, they did have access to a resource they shouldn't have access to.
In that regard, you can try to mitigate the attack using, like you mentioned, a nonce. Just don't forget to protect that nonce by a key that is related to the identity or session of the JWT. Alternatively you can add an HOTP or TOTP, or some unique signature to the request. This comes at a cost of you having to create extra logic at both your client and server.
So summarised, JWT's themselves don't really provide security, they provide authentication. Generally speaking JWT's are secure if using contemporary security measures such as SSL. If you really want to add additional security to the request, you are left to implement additional logic, such as OTP's or signatures by implementing more logic at the client and server.
I've not been able to find decent information in the docs for this. Here's to the internet :)
This is my current understanding:
The documented approach is to create a ContentKeyPolicy with JWT restriction and Media Services will expect the claim added to the token of urn:microsoft:azure:mediaservices:contentkeyidentifier=INJECTED CONTENT KEY ID HERE based on what content the locator URL is serving up.
This means I'd need a new content key for every SKU sold to secure access to the media. Is there a way to hook into this authorization logic to say "I want you to call this API to run my custom validation" where I could check the JWT user's purchased content? This way only one content policy is really needed and becomes manageable.
The custom scenario you described is exactly the reason for using unique content key identifiers.
The way the key delivery server works with JWT tokens is that the key delivery server first checks to see which content key ID is being used. It then checks to see if the token is properly signed with the primary verification key that was used for that locator. Then it validates any claims that were applied when the encryption policies were set.
I'd recommend tracking the primary verification key (if unique per locator), the locator itself, the content key ID, and any claims in your own database so that all of those values are readily accessible for any of your content.
I have a backend which exposes a RESTful API which is currently 'free for all' (but uses https).
I now want to add RBAC (role-based access control) and JWT seems the way to go and I read a lot about JWT, but don't see the advantage of using RSA over SHA to sign the token.
Assumption is that the user has authenticated and obtained a key, be it shared or public/private.
Now, it seems to me that in both cases - SHA or RSA HMAC - both parties (client and server) must have the shared key, or their half of the private/public key in the case of RSA. And the server must find that key (in a table or database) based on a claim in the JWT in order to verify the token's signature. Once it has confirmed the purported user in the JWT it will then authorise the request using the configured roles.
So what are the advantages of RSA in that scenario ?
I assume you're talking about RSxxx (e.g. RSA256) and HSxxx (e.g. HS256 (HMAC-SHA256)) algorithms here. The main difference is that HS256 is an symmetric algorithm while RS256 is an asymmetric algorithm. Symmetric algorithms just use one key (or secret) for signing and verifying, whereas asymmetric algorithms use the private key to sign and the public key to verify the token.
If you share the secret used for HS256, everyone knowing the secret could issue or modify and re-sign a token. That would defeat the purpose of the signature if you share the secret with the client. In case of RS256 or any other asymmetric algorithm, only the authentication server knows the private key and anyone who need to verify the token can use the public key to do so. The matching key is usually identified by the KID (Key Id) claim in the header of the token.
But usually, signing and verifying is only done on server side, the client does not need to verify the token and thus does not need to know the key or secret at all. Therefore you can in case of a simple service, when authentication and resource server are the same, still rely on a symmetric algorithms. But once you have one separate authentication server for several resource servers, asymmetric algotrithms should be used.
Thanks for the response, that does help make it clearer.
So basically, for a simple RESTful API, there is no real advantage using RSA over HSA.
Some points that may help others about token-based authentication:
Preamble: the following are all in the context of using SSL.
Firstly, a token is a substitute for username/password credentials: if a client has a token, it is equivalent to having username/password. It took me a while to figure that out. A bit like using a badge at a corporate printer: instead of entering username and password you just place your badge (the token) on the printer and it knows who you are and prints your document.
However, tokens make using an API much simpler because
the client simply adds its token to the http header,
the server only verifies the token,
neither have to deal with authentication flows involving username/pw and managing session cookies.
But the downsides are that
losing the token is like losing the username/password, and
in a complex system involving many components, tokens would have to be shared across all involved backend servers.
Secondly, the client doesn't strictly need to verify the token - it only needs the token - if someone gives you a key to their house or car, you don't typically check the key, you trust the person (maybe sometimes foolishly so) and use it. So a simple random string can serve as a token; the server maintains a simple table correlating tokens to users, no keys involved at all. If a client sends a token that the server doesn't have --> access denied. If it has a matching token --> look up the user that correlates to the token (typically followed by authorisation).
Thirdly, the server typically generates a token either based on trusting the client, or after the client has somehow authenticated, e.g . oauth. Afterwards, the client just sends the token with every request and the server looks it up in its table. However, such server-side tables for random-string tokens may become large and have to be persistent, so either a database or a file is required, and they are typically comparably slow, require maintenance etc, so enter using cryptographic signatures and jwt:
Fourthly, tokens with signature:
the server signs the token and sends it to the client - but the server does not have to store it, also no session cookies as described above
the client stores the token securely and sends it with every subsequent request (just like with a random string token)
the server receives the request, calculates the signature of the jwt, and compares it with the signature of the token sent by the client. Note that there is no file or DB lookup, only computing the signature again and comparing it with the signature sent by the client. If the signatures match then the token must be the same as the one the server issued and hence the jwt header and payload are also the same as issued by the server
the server now interprets the payload, esp. the user (and typically performs authorisation)
So, using jwt means the server does NOT need
a database or file with user names and tokens
to save tokens
to maintain session cookies
It only needs to create and compare a signature. And for that it needs a cryptographic key. This can be a symmetric key for a simple API or an asymmetric key for more complex systems where public keys must be shared.
Hope this helps some other tortured souls who grappled with this topic.
I'm working on a project that uses jwt (json web tokens) to check whether a user is authenticated with the system.
The services are completely stateless, so I can easily scale from one instance to a few dozens. There is only one issue. To be able to validate the jwt on every instance, I need to synchronize the symmetric secret key between the instances.
Of course I could build a system that uses some sort of service discovery and exchanges the symmetric key by encrypting it with an asymmetrical encryption. This just doesn't feel like a proper method.
I could set a fixed key on every instance but changing the key, which effectively invalidates all the previously created tokens, would be a pain.
I don't want to set a master instante every other instance is relying on.
My third idea was using an asymmetrical approach and letting each instance create their own key pair. By writing the issuer in the token, the instance that gets called could retrieve the public key from the instance that issued the token and validate the token this way.
It's not like I don't have any ideas. I just don't really like my ideas so far.
Do you have any best practices to solve such a problem?
I'm in the process of rolling my own JWT token auth, however, I would really like it to be a one time-token – so once it's used, the server generates a new token and the client will have to use that token during the next request/call.
However, it has come to my understanding that JWT is supposed to be 'stateless' – but with the approach of a one time token, I guess I would need to somehow store the valid tokens, since the token will be refreshed once it's used. Or is there any way to avoid storing a value on the server, and still be able to create one-time tokens?
The two main reasons for why I don't want to store any value is first of all scalability (sure, I could have cache-server inbetween to store the values, but it would be nice if that wasn't required), secondly, JWT is supposed to be stateless from my understanding, which it wouldn't be if I need to store a value on the server to be able to validate the token.
Any ideas?
Use the user's current password's hash for signing the JWT token, in this way all tokens generated before a successful password change would get invalidated the next time. I got the idea from here https://www.jbspeakr.cc/howto-single-use-jwt/.
Solutions exist, of course.
As with any distributed system (you mentioned scalability) you have to choose between availability and consistence.
You choose availability. In this case you could maintain a list of already-used tokens that you replicate in a eventually consistent manner between all the endpoints. For example when a token is used the respective endpoint send that token to the other endpoints in the backgound. There is however a (short) time frame when that token can be used a second time by another endpoint until that endpoint is updated.
You choose consistency (you won't allow a token to be used multiple times whatsoever). In this case you use a central database with already-used tokens and you check that database everytime you need to perform an action. Scalability? You could use sharding on the token and have n databases, each one being responsible for a tokens subset.
It depends on your business what solution fits best.
Not really no, a JWT token is valid if it hasn't expired and the signature is correct, commonly people will keep a DB of blacklisted tokens which are usually ones where people have logged out etc.
The only sensible way I can think of is give them a short expiry time and maintain a list of tokens that have already been used, you'd then periodically remove the ones that subsequently expire from the DB.
There are actually some DB's that have a TTL on records (dynamoDB, mongodb) so you'd just put the tokens in and set a TTL for when the token expires.
Update 2022
Just to be clear JWT tokens AREN'T stateless they have claims that, as long as they're signed by the right private key - give you a stateful piece of data that can be reissued by your API to reflect the current state of the user.
You'd just need to handle token re-issue on the consumer.
Like others have mentioned, it depends on your business case. Password resets links can be like mentioned on https://www.jbspeakr.cc/howto-single-use-jwt/.
If you have the Single-Use & Single-Auth scenario, where you might want to invalidate any previously used and unused token, you can store a single nonce and update it on every new token request and also when its used.