JWT: what's the most secure (at today) of signature algorithms? - jwt

I'm reading https://jwt.io/ docs and found that actually supported algos are
HS256
HS384
HS512
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
Which of this is the most secure?
I know that both parties (client and server) must use the same algo so it must be supported on both client and server sides.

The choice is really less about security and more about what you are using JWTs for - who can create/verify them, whether keys are shared, algorithm speed and so on. RSA and ES use public key cryptography so are used for situations where one trusted party creates a token which can be verified by others (but the others can't create tokens themselves). HMAC is much faster than RSA but requires that both the signer and verifier use the same key (which means they can both create tokens).
As a real example, client authentication in OpenID can use a JWT which is HMAC signed using the secret key that the client and authorization server share. However HMAC would not be an appropriate algorithm for JWT tokens issued by the authorization server to represent things like client grants or ID tokens, since a malicious client application could then forge these tokens and impersonate the authorization server.
Algorithms using a larger hash are theoretically stronger (e.g. HS512 vs HS256) but in practice someone cracking the JWT algorithms in your system is unlikely to be a major concern compared with other security issues.
This is probably a better question for the crypto site, rather than SO and you should have a look there. See, for example this answer and this one.

Related

How replication of signed JWT Tokens are prevented?

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.

Assymetric signing algorithms for JWT signing

JWT noob here, so sorry if this is a stupid question: Is it possible to sign JWTs with assymetric keys/certificates/etc?
If I understand JWTs right, the idea is that the client can authenticate to the server with them because they contain a signature the server can check.
All the examples I've seen online rely on the same secret key for creating and verifying the JWT.
Now, if I wanted to issue JWTs for different servers and did it like that, I'd have to give them my secret key (probably one for each server), and they'd be able to issue JWTs with it. I might not want to allow that. Also each server could only verify JWTs that were created specifically for it or one with the same key.
On the other hand, I do know that things can be signed with assynchronous algorithms in such a way that you can verify the signature with a public key, but sign stuff only with the private key.
That would solve the problem, because each server that wants to accept JWTs my server signed only has to download my public key. Does such a thing exist in JWT?
I think you mean an asymmetric algorithm, not an asynchronous algorithm.
The short answer is yes - you can use an asymmetric algorithm like RS512 to sign a token with a private key and then validate it with the matching public key. This way you don't have to share the secret outside of the service that signs the token.
Note that different libraries may support different algorithms, so make sure to check which algorithms the library you use supports. JWT.io has a pretty comprehensive listing of which libraries support which algorithms.

What advantage does signing a JWT with RSA have over SHA in the contect of a RESTful API?

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.

How can JWT be verified outside the authorization server

Recently, I'm trying to implement an OAuth2.0 server using JSON Web Token (JWT) as access token. I'm very confused about the self-contained feature of JWT. I notice that JWT can be verified anywhere, not mandatorily in authorization server because it is self-contained. How does this feature work? What claims should be included in JWT in order to realize self-contained feature?
Another question is that, if JWT is stateless, it means the server should not store the JWT. Then how is the JWT verified? Can't it be easily forged?
I'm the rookie in this field, I wish someone could help me out:)
JWT contains claims that can be signed, encrypted or both.
These operations are performed using cryptographic keys. Keys can be symmetric (e.g. octet keys) are Asymmetric (e.g. private/public key pairs such as RSA or EC keys).
When you want to verify a JWT (i.e. a JWS), you have to perform the following steps:
Check the header (algorithm is supported, critical claims are in the payload and their value are understood).
Check the claims (especially exp, iat, nbf, aud).
Check the signature.
To check the signature, you need the key and, depending on the algorithm, this key can be
The symmetric key
The public key if asymmetric
When you want to allow third party applications to verify your JWT, you will use asymmetric keys and share the public key with the third parties.
As public keys cannot be used to sign, third parties cannot forge a valid token with custom claims.
The way you share the keys is up to you. The common way is to provide an URL where applications will retrieve them (e.g. Google keys at https://www.googleapis.com/oauth2/v3/certs).

What is the current standard for authenticating Http requests (REST, Xml over Http)?

The standard should solve the following Authentication challenges like-
Replay attacks
Man in the Middle
Plaintext attacks
Dictionary attacks
Brute force attacks
Spoofing by counterfeit servers
I have already looked at Amazon Web Services and that is one possibility. More importantly there seems to be two most common approaches:
Use apiKey which is encoded in a similar fashion like AWS but is a post parameter to a request
Use Http AuthenticationHeader and use a similar signature like AWS.
Signature is typically obtained by signing a date stamp with an encrypted shared secret. This signature is therefore passed either as an apiKey or in
the Http AuthenticationHeader.
I would like to know weigh both the options from the community, who may have used one or more and would also like to explore other options that I am not
considering. I would also use HTTPS to secure my services.
"authentication" means:
prove me you are who you say you are
"who you are" is the identity of an entity (person, computer user, software, server, etc...)
"identity" is an attribute unique to each entity (a dba would say primary key here)
so you must prove to have that unique attribute in a way or another.
When the entity here is an HTTP client, then HTTP Auth is the standardized way to prove to the server its unique identity (represented by what we call a user name).
It does not bother with the security of the channel, that's what the presentation layer (ie., SSL) is for, and requires a shared secret between the parts. "Shared secret" means that both parts must know it and no one else does. This implies the two parts trust each other on not disclosing the secret or taking appropriate measures if it gets disclosed (changing the secret, for example).
HTTP as a protocol does not include other ways to do authorization and leaves that at other layers. As an example, SSL can prove the identity of the two parties without sharing a secret via the use of a public key infrastructure (certificates and certification authorities).
In the end:
if it's ok for you to share a secret between the parties, you can use HTTP Auth for authentication and SSL to secure the channel. It's up to the parties to securely exchanging and storing the shared secret
if you don't want to share a secret, but the parties can agree on a common trusted third party, you can speak plain HTTP and use SSL for both securing the channel and proving the identity of one or both parties using a PKI (> certificates)
there are many other possibilities but this two are the most standard I can think of and should be compatible with most of the existing HTTP softwares/libraries/whatevers out there
home brew systems, while technically valid, will either break accepted standards or be ad-hoc (hence non standard) systems implemented at the application layer (to solve an issue that should be addressed at another layer, bah)
There are no ways to prove the uniqueness of something without agreeing on a shared secret (and keeping it secret) or agreeing to trust someone else to take care of that uniqueness (PKI). Everything else is just implementation details.
I'm not certain there is one standard. If there is it would likely be HTTP Auth, (Basic or Digest). Both of the aforementioned are pretty poor solutions.
AWS is a good example of how a "roll-your-own" auth solution could work, however, when you're talking about security/authentication, roll-your-own is usually a bad idea unless you're a security/crypto guru.
My preferred choice is actually just using Client Side Certificates. It takes care of the authentication and security process. No need for an API Key because the Cert itself identifies the client user.