We are making use of RemoteJWKSet in nimbus-jose-jwt third party library for JWKS endpoint based JWT validation.
With RemoteJWKSet, we can retrieve the JWKS from a remote endpoint and the retrieved JWK set is cached in order to to minimize network calls.
Also it is capable of handling key rotation at the remote server since the cache is updated whenever the key selector tries to get a key with an unknown KID.
My question is that, let's say a particular key set is removed from the remote JWKS endpoint due to security reasons. But when we get a JWT that was signed using the removed key, it will still be valid since that keyset is available in the cache (RemoteJWKSet will only update the cache when it gets a token with an unknown KID).
I need to know is there any possible way to invalidate the cached JWK set in RemoteJWKSet if required other that restarting the server?
Raised the same question at connect2id support portal [1]
They have suggested to put an empty JWK set which will cause the RemoteJWKSet to reload the key set from the URL on the next call as a mechanism to invalidate the JWKS cache.
[1] https://bitbucket.org/connect2id/nimbus-jose-jwt/issues/287/how-to-invalidate-cache-of-remotejwkset-in
Related
I am trying to implement a JWT Token/RefreshToken Auth Backend server.
There is a lot of resources out there, and it has been really helpful, but somehow nothings tell me how/where to save my refresh tokens.
I am working so far with a mongo db to store the information of my app. Is it safe to store my refresh token in the same db? Is there any more secured, or more performant solution I am not seeing?
Ideally, you should not even have to store your access or refresh tokens in any database. One of the main motivations behind the JWT pattern was to eliminate the need to persist session state in the server. Instead, the session state is maintained in the JWT tokens themselves. To better understand this, let's examine the simplest sequence of events when the server receives an incoming access token.
When the server receives an incoming access token, the first thing it will do is to check the claims section of that token. One of the claims, typically called exp, contains the token expiry date. Any access attempt in the server which uses an expired token will be rejected. The server also can ensure that the incoming JWT has not been tampered with by computing the checksum. Any token whose expiry or other claims have been doctored would fail the checksum test.
The main point here is that ideally a JWT acts as a standalone passport of sorts. There should not be a need to store it in a database for comparison or lookup. Sometimes, there might be a need to blacklist certain JWT. In this case, the need might arise to store them on the server. But here we would still not use a database, but rather a lightweight cache with really fast access times. And, we would only be storing a very small number of blacklisted JWT, so the server would still remain largely stateless.
I'm having trouble understanding how exactly JWTs are used in conjunction with RSA encryption. This is my current understanding for RSA:
-The client logs makes a post request to the server with his credentials, if the credentials are valid the server signs a JWT using the private key and sends it to the client.
-The client uses the public key to verify the JWT came from the server and then stores this JWT for future requests.
Now does the client just attach this JWT to the header of each get/post request I make to protected routes in order to verify the user? Wouldn't this be vulnerable to a man in the middle attack since they could easily change the contents of the request and the server would have no way to know it's been modified. How am I supposed to hash the header + payload to stop an entity from changing the data like with HMAC?
The critical piece of information/understanding you seem to be missing here is that JWTs contain a checksum, which is a hash dependent on the contents of the JWT. The server will sign every JWT with its private key before it sends it back to the client, including a checksum. Upon receving an incoming JWT, the JWT will again compute the checksum based on the contents and compare to the checksum which the token itself contains. In the event of a man-in-the-middle attack, which attempted to insert or alter the contents of the JWT, the checksum computed would not match the value embedded in the JWT. You might ask next what would prevent the man-in-the-middle from also computing the correct checksum. Well, MITM can't do that, not without having the server key. The hash should largely be impossible to reverse engineer out the key used to sign it. So as long as you defend your server key from being hijacked, the JWT pattern can actually be very secure.
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.
What happens when the signing certificate (used for signing jwt tokens) expires when using IdentityServer 3?
It's unclear to me and I can't find any documentation, other than that it's possible to get a warning that it has expired. (Ref. https://identityserver.github.io/Documentation/docsv2/configuration/events.html)
Is there any mechanism that stops the use of expired signing certs?
And what happens on the client side (client being the Web API that uses IdentityServer for authentication) when validating a token signed by an expired certificate? (For example if https://github.com/IdentityServer/IdentityServer3.AccessTokenValidation is used as a middleware.)
Well I've just tested this (on IdentityServer4) and it seems to continue to work happily with an expired signing certificate, here's my test cert's validity:
I'm able to login, get an ID token and an access token and then access an API with the access token. What IdentityServer does do however is to log a warning:
2017-07-13 12:15:54.871 +02:00 [Warning]
Certificate "CN=test_expired_signing_certificate" has expired on "13/07/2016 14:14:37"
This matches what the IdentityServer (3) docs say here:
IdentityServer raises a number of events at runtime, e.g:
snip...
Expired/invalid/no signing certificate
By default these events are forwarded to the configured log provider - a custom event service can process or forward them in any way suitable for the environment.
So this would be your way of detecting it when it's already too late. A better option is to rollover signing keys periodically and within the validity of the keys, this is the common approach which also allows for a compromised key to be revoked if necessary. See this issue where the process is discussed, basically IdentityServer can handle two keys:
[Middleware refreshes] the metadata document ... once a day.
The metadata doc can hold 2 keys - primary and secondary and the middleware will load and use both when present (JWTs have a key identifier that allows picking the right one).
When you start to rollover - set both keys and at some point swap primary and secondary.
Disclaimer: I never worked with IdentityServer3
The outside world doesn't know your certificate and therefore doesn't know it's expired. The outside world merely sees your public key at:
YourIdentityServer.com/.well-known/openid-configuration
or more accurately:
YourIdentityServer.com/.well-known/openid-configuration/jwks
You can play around with this: Create a new cert on startup (see https://gist.github.com/mykeels/408a26fb9411aff8fb7506f53c77c57a). Even if you set the TimeSpan to one minute, it will keep working.
But once you wait 1 minute and restart your IdentityServer your token from last sign in will be considered invalid, because it was created with the now outdated signing key. It is checked against the new public key and fails.
It seems to be recommended to periodically replace your cert with a new one, while also keeping the previous key around, see "signing key rollover":
https://docs.identityserver.io/en/dev/topics/crypto.html#signing-key-rollover
I am building a RESTful API with multiple servers and I want to know if it's okay to store the access token in a central database server and then, for every request, verify if this access token is valid by querying the database and then performing the action given.
If I use sessions for this job, will it become non RESTful? Like even if I store the session data in a database? It's been a confusing idea to me for so long.
REST is stateless
REST stands for Representational State Transfer and this architecture was defined by Roy Thomas Fielding in the chapter 5 of his dissertation.
Fielding defined a set of constraints for the REST architecture. One of these constraints is the stateless communication between client and server, defined as following (the highlights are not present in his dissertation):
5.1.3 Stateless
[...] each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. [...]
So, if you keep the session state on the server, you break the stateless constraint. Hence, it's not REST. In REST you won't have a session on the server and, consequently, you won't have session identifiers.
Each request must contain all data to be processed
Each request from client to server must contain all of the necessary information to be understood by the server. With it, you are not depending on any session context stored on the server.
When accessing protected resources that require authentication, for example, each request must contain all necessary data to be properly authenticated/authorized. It means the authentication will be performed for each request.
Have a look at this quote from the RFC 7235 regarding considerations for new authentication schemes:
5.1.2. Considerations for New Authentication Schemes
There are certain aspects of the HTTP Authentication Framework that
put constraints on how new authentication schemes can work:
HTTP authentication is presumed to be stateless: all of the
information necessary to authenticate a request MUST be provided
in the request, rather than be dependent on the server remembering
prior requests. [...]
And authentication data (credentials) should belong to the standard HTTP Authorization header. From the RFC 7235:
4.2. Authorization
The Authorization header field allows a user agent to authenticate
itself with an origin server -- usually, but not necessarily, after
receiving a 401 (Unauthorized) response. Its value consists of
credentials containing the authentication information of the user
agent for the realm of the resource being requested.
Authorization = credentials
[...]
Please note that the name of this HTTP header is unfortunate because it carries authentication data instead of authorization. Anyways, this is the standard header for sending credentials.
Token based authentication
When performing a token based authentication, the tokens are your credentials. In this approach, your hard credentials (username and password) are exchanged for a token that is sent in each request. Again, the authentication must be performed for every request, so you won't take advantage of any stored context on the server.
It's perfectly valid storing your tokens somewhere in your server. And it won't break the stateless constraint of the REST architecture.
Tokens
Basically, the tokens can be opaque (which reveals no details other than the value itself, like a random string) or can be self-contained (like JSON Web Token):
Random String: A token can be issued by generating a random string and persisting it to a database with an expiration date and with a user identifier associated to it.
JSON Web Token (JWT): Defined by the RFC 7519, it's a standard method for representing claims securely between two parties. JWT is a self-contained token and enables you to store a user identifier, an expiration date and whatever you want (but don't store passwords) in a payload, which is a JSON encoded as Base64. The payload can be read by the client and the integrity of the token can be easily checked by verifying its signature on the server. You won't need to persist JWT tokens if you don't need to track them. Althought, by persisting the tokens, you will have the possibility of invalidating and revoking the access of them. To find some great resources to work with JWT, have a look at http://jwt.io.
There are many databases where you can persist your tokens. Depending on your requirements, you can explore different solutions such as relational databases, key-value stores or document stores.
Your RESTful API would need to be stateless. Stateless means, that it should not rely on prior communication, like in the case of authentication and cookies set before the request in question.
That does not mean however that you can not cache some authentication token on the server side, provided, that a client could make a request without it. This all means, that if the client can fall back to standard HTTP authentication on every request, it should still be ok. The goal with this is to enable load balancing, distribution, and no (or limited) memory use on the server side for conversations.
Other than that, you don't really need to follow all the "rules" if you are not planning to use the benefits it provides. You can, if you want, implement it any way you want as long as the tradoffs are known.
Edit: found a previous discussion on the topic: Do sessions really violate RESTfulness?