Specify alg when verifying JWT token - jwt

In jsonwebtoken 8.5.1, the token can be verify as for HS256 as example:
const jwt = require("jsonwebtoken");
const decoded = await jwt.verify(jwt_token, jwtPrivateKey, {ignoreExpiration: true});
Since alg:none is a known vulnerability, is there a way to force expected alg used when verifying? Also does it enhance the security by specifying alg in verifying?

You can specify the algorithm you expect with the algorithms key, see the documentation of jwt.verify():
algorithms: List of strings with the names of the allowed algorithms. For instance, ["HS256", "HS384"].

Related

What is the difference between JOSE, JWA, JWE, JWK, JWS and JWT?

What is the difference between JOSE, JWA, JWE, JWK, JWS and JWT and how are they related to one another?
JOSE stands for JSON Object Signing and Encryption. It's a set of standards used to sign and encrypt data using JSON-based data structures. In other words, JWA, JWE, JWK, JWS, and JWT are all part of JOSE.
TL;DR:
JWA: Defines a set of crypto algorithms and identifiers used in JWE, JWK and JWS.
JWK: Defines a representation of crypto keys used as input for the algorithms defined in JWA using JSON-based data structures.
JWE: Defines encrypted content using JSON-based data structures. The encryption/decryption is performed with the algorithms defined in JWA.
JWS: Defines signed content using JSON-based data structures. The signing/verification is performed with the algorithms defined in JWA
JWT: Defines subject claims using JSON-based data structures. The claims can be optionally protected via JWE or JWS.
Longer version:
JWE (JSON Web Encryption) represents encrypted content using JSON-based data structures. JWE is used to share data between parties with authentication (ensure data comes from sender it claims to be), confidentiality (ensure only receiver can decrypt data), and integrity (ensure data was not altered by a third-party during transit). JWE supports both symmetric key cryptography (single key used to encrypt and decrypt) and asymmetric key cryptography (public key used to encrypt, private key used to decrypt).
JWS (JSON Web Signture) represents content secured with digital signatures or Message Authentication Codes (MACs) using JSON-based data structures. JWS is used to share data between parties with authentication and integrity. JWS provides a lighter weight counterpart to JWE when confidentiality is not required. JWS supports symmetric key-based MACs (single key used to sign and verify) and asymmetric key-based digital signatures (private key used to sign, public key used to verify).
JWE encryption and JWS signing is performed using a cryptographic algorithm. These algorithms and their corresponding identifiers are defined in JWA (JSON Web Algorithms).
The cryptographic algorithms specified in JWA use cryptographic keys as input. JWK (JSON Web Key) defines a representation of cryptographic keys using JSON-based data structures.
JWT (JSON Web Token) is a compact, URL-safe means of representing claims about a subject to be transferred between two parties. A JWT is a form of claims-based identities used in claims-based authentication. JWTs can be optionally protected via JWE or JWS. The minimal representation of a JWT consists of a JOSE header and the claims (also known as payload in the context of JWS and plaintext in the context of JWE).
Here are three JWT values for the claim { "foo": "bar" }:
Unprotected (no signature/encryption):
Minimum JOSE header is: { "alg": "none" }
JWT value is: eyJhbGciOiJub25lIn0.eyJmb28iOiJiYXIifQ (header + "." + claims)
Protected via JWS:
Using JWA with id: HS256 (HMAC using SHA-256)
Using JWK with value: { "kty": "oct", "k": "AAECAwQFBgcICQoLDA0ODwABAgMEBQYHCAkKCwwNDg8" }
Minimum JOSE header is: { "alg": "HS256" }
JWT value is: eyJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.QqnxrmVYNzUZe2xJeSZIBMoELSfxW144gSAvdBTeXCo (header + "." + payload + "." + signature)
Protected via JWE:
Using Key Management Mode: dir (Direct Encryption)
Using JWA with id: A256GCM (AES GCM using 256-bit key)
Using JWK with value: { "kty": "oct", "k": "AAECAwQFBgcICQoLDA0ODwABAgMEBQYHCAkKCwwNDg8" }
Minimum JOSE header is: { "alg": "dir", "enc": "A256GCM" }
A possible JWT value is: eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..69fkCssY6yzSKVtt.3kRb3CHlZdwB1kBrwQ.mkwzT_wBpi6W7mXgjbxmvw (header + ".." + initialization vector + "." + ciphertext + "." + authentication tag)
Note: The word "possible" is used in the JWE example because the IV (initialization vector) is randomly-generated. Thus there are many valid variants of the same JWT claims encrypted with JWE using the same key.

Azure KeyVault signature fails during verification using javascript libraries intermittently

I am using Azure key vault for creating and storing my Secp256k1 keys. I am also using the sign API for getting my input string signed. I am working on a Secp256K1 blockchain network.These are steps I follow to get the signature in Golang.
Converting my Hex string into Byte[]
Sha256 of this Byte[]
RawURL encoding of this Sha.
b64.RawURLEncoding.EncodeToString(sha)
Sending this to Key vault for signature.
Decoding the response using RawURLEncoding.
b64.RawURLEncoding.DecodeString(*keyOpsResp.Result)
Doing Hex of the []Byte array returned from 5th Step.
Sending the signature to the blockchain.
The problem I am facing is that signature is invalid sometimes. As in 2/5 times it works and other times signature verification fails.
I am thinking there is some special chars or padding thing that I am missing.
How can I resolve this?
PS: Azure uses non-deterministic signatures where as chains usually use deterministic signs. I did some reading and found out that for verification it does not matter both could be verified successfully. Let me know if I am wrong.
• Since you are using base64 encode RawURL for encoding purposes, you can check whether the following parts are included in the token request for the keyvault signature validation. They are as follows: -
aud (audience): The resource of the token. Notice that this is https://vault.azure.net. This token will NOT work for any resource that does not explicitly match this value, such as graph.
iat (issued at): The number of ticks since the start of the epoch when the token was issued.
nbf (not before): The number of ticks since the start of the epoch when this token becomes valid.
exp (expiration): The number of ticks since the start of the epoch when this token expires.
appid (application ID): The GUID for the application ID making this request.
tid (tenant ID): The GUID for the tenant ID of the principal making this request. It is important that all the values be properly identified in the token for the request to work
• Also, please check the size of the block that is dependent on the target key and the algorithm to be used for validation of signature. In that, please check the ‘decryptParameters’, ‘algorithm’ and ‘ciphertext’ parameter for the returns that are displayed after the decrypt operation during signature validation.
Please find the below links for more details: -
https://learn.microsoft.com/en-us/java/api/com.azure.security.keyvault.keys.cryptography.cryptographyasyncclient.decrypt?view=azure-java-stable

Why JWT Token signing key is required

JWT tokens required signing key to decode them, but in https://jwt.io/ it can be decoded without any signing key, how is this possible.
You do not need a key to open the encoding, you need a key to verify that nobody changed the contents of the JWT. In fact the string you see is just json's base64 with your information, metadata, and "signature" on all content.
The signature is the most important part of a JSON Web Token(JWT). A signature is calculated by encoding the header and payload using Base64url Encoding and concatenating them with a period separator. Which is then given to the cryptographic algorithm.
// signature algorithm
data = base64urlEncode( header ) + “.” + base64urlEncode( payload )
signature = HMAC-SHA256( data, secret_salt )
So when the header or payload changes, the signature has to calculated again. Only the Identity Provider(IdP) has the private key to calculate the signature which prevents the tampering of token.
read more:
https://medium.com/#sureshdsk/how-json-web-token-jwt-authentication-works-585c4f076033
https://jwt.io/introduction/
https://www.youtube.com/watch?v=7Q17ubqLfaM

SHA256, SHA1, SHA384 hash to JSON Web Token

Is it possible to generate a JSON Web Token from a SHA384 Hash. If it is possible please advice how it is possible.
Also please generate JSON Web Token from my SHA384 hash:
e648d207eb6a457cc3b415e5e6db38759de529051d808b5d34c679c43020a233e6b5161de2e85070127009d61e4c24c8
No, converting a hash into a JWT token is not possible and I also can't see why/for what anyone would want this.
As mentioned in the comment, that approach does't make any sense at all.
A hash doesn't contain any readable information that you could convert into anything.
You could create a token that contains a hash in the payload, if this is what you mean.
JWTs are usually signed. The SHA algorithm, e.g. HS256 (HMAC-SHA256), can be used to sign a token.
That means that a hash is calculated from the header and payload plus your secret and the hash value is then base64url encoded and attached to the token as a signature.
You can read this introduction to learn more about JWT.
Yes it is possible in Laravel version 7.
While converting jwt hash token to shal, go to EloquentUserProvider.php
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
if(sha1($plain) == $user->getAuthPassword()) {
return true;
}else {
return false;
}
// return $this->hasher->check($plain, $user->getAuthPassword());

When would you use an unprotected JWS header?

I don't understand why JWS unprotected headers exist.
For some context: a JWS unprotected header contains parameters that are not integrity protected and can only be used per-signature with JSON Serialization.
If they could be used as a top-level header, I could see why someone could want to include a mutable parameter (that wouldn't change the signature). However, this is not the case.
Can anyone think of a use-case or know why they are included in the spec?
Thanks!
JWS Spec
The answer by Florent leaves me unsatisfied.
Regarding the example of using a JWT to sign a hash of a document... the assertion is that the algorithm and keyID would be "sensitive data" that needs to be "protected". By which I suppose he means "signed". But there's no need to sign the algorithm and keyID.
Example
Suppose Bob creates a signed JWT, that contains an unprotected header asserting alg=HS256 and keyid=XXXX1 . This JWT is intended for transmission to Alice.
Case 1
Suppose Mallory intercepts the signed JWT sent by Bob. Mallory then creates a new unprotected header, asserting alg=None.
The receiver (Alice) is now responsible for verifying the signature on the payload. Alice must not be satisfied with "no signature"; in fact Alice must not rely on a client (sender) assertion to determine which signing algorithm is acceptable for her. Therefore Alice rejects the JWT with the contrived "no signature" header.
Case 2
Suppose Mallory contrives a header with alg=RS256 and keyId=XXX1. Now Alice tries to validate the signature and finds either:
the algorithm is not compliant
the key specified for that algorithm does not exist
Therefore Alice rejects the JWT.
Case 3
Suppose Mallory contrives a header with alg=HS256 and keyId=ZZ3. Now Alice tries to validate the signature and finds the key is unknown, and rejects the JWT.
In no case does the algorithm need to be part of the signed material. There is no scenario under which an unprotected header leads to a vulnerability or violation of integrity.
Getting Back to the Original Question
The original question was: What is the purpose of an unprotected JWT header?
Succinctly, the purpose of an unprotected JWS header is to allow transport of some metadata that can be used as hints to the receiver. Like alg (Algorithm) and kid (Key ID). Florent suggests that stuffing data into an unprotected header could lead to efficiency. This isn't a good reason. Here is the key point: The claims in the unprotected header are hints, not to be relied upon or trusted.
A more interesting question is: What is the purpose of a protected JWS header? Why have a provision that signs both the "header" and the "payload"? In the case of a JWS Protected Header, the header and payload are concatenated and the result is signed. Assuming the header is JSON and the payload is JSON, at this point there is no semantic distinction between the header and payload. So why have the provision to sign the header at all?
One could just rely on JWS with unprotected headers. If there is a need for integrity-protected claims, put them in the payload. If there is a need for hints, put them in the unprotected header. Sign the payload and not the header. Simple.
This works, and is valid. But it presumes that the payload is JSON. This is true with JWT, but not true with all JWS. RFC 7515, which defines JWS, does not require the signed payload to be JSON. Imagine the payload is a digital image of a medical scan. It's not JSON. One cannot simply "attach claims" to that. Therefore JWS allows a protected header, such that the (non JSON) payload AND arbitrary claims can be signed and integrity checked.
In the case where the payload is non-JSON and the header is protected, there is no facility to include "extra non signed headers" into the JWS. If there is a need for sending some data that needs to be integrity checked and some that are simply "hints", there really is only one container: the protected header. And the hints get signed along with the real claims.
One could avoid the need for this protected-header trick, by just wrapping a JSON hash around the data-to-be-signed. For example:
{
"image" : "qw93u9839839...base64-encoded image data..."
}
And after doing so, one could add claims to this JSON wrapper.
{
"image" : "qw93u9839839...base64-encoded image data..."
"author" : "Whatever"
}
And those claims would then be signed and integrity-proected.
But in the case of binary data, encoding it to a string to allow encapsulation into a JSON may inflate the data significantly. A JWS with a non-JSON payload avoids this.
HTH
The RFC gives us examples of unprotected headers as follows:
A.6.2. JWS Per-Signature Unprotected Headers
Key ID values are supplied for both keys using per-signature Header Parameters. The two JWS Unprotected Header values used to represent these key IDs are:
{"kid":"2010-12-29"}
and
{"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"}
https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.6.2
The use of kid in the example is likely not coincidence. Because JWS allows multiple signatures per payload, a cleartext hint system could be useful. For example, if a key is not available to the verifier (server), then you can skip decoding the protected header. The term "hint" is actually used in the kid definition:
4.1.4. "kid" (Key ID) Header Parameter
The "kid" (key ID) Header Parameter is a hint indicating which key was used to secure the JWS. This parameter allows originators to explicitly signal a change of key to recipients. The structure of the "kid" value is unspecified. Its value MUST be a case-sensitive string. Use of this Header Parameter is OPTIONAL.
https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.4
If we look at Key Identification it mentions where you a kid does not have to be integrity protected (ie: part of unprotected headers): (emphasis mine)
6. Key Identification
It is necessary for the recipient of a JWS to be able to determine the key that was employed for the digital signature or MAC operation. The key employed can be identified using the Header Parameter methods described in Section 4.1 or can be identified using methods that are outside the scope of this specification. Specifically, the Header Parameters "jku", "jwk", "kid", "x5u", "x5c", "x5t", and "x5t#S256" can be used to identify the key used. These Header Parameters MUST be integrity protected if the information that they convey is to be utilized in a trust decision; however, if the only information used in the trust decision is a key, these parameters need not be integrity protected, since changing them in a way that causes a different key to be used will cause the validation to fail.
The producer SHOULD include sufficient information in the Header Parameters to identify the key used, unless the application uses another means or convention to determine the key used. Validation of the signature or MAC fails when the algorithm used requires a key (which is true of all algorithms except for "none") and the key used cannot be determined.
The means of exchanging any shared symmetric keys used is outside the scope of this specification.
https://datatracker.ietf.org/doc/html/rfc7515#section-6
Simplified, if you have a message that by somebody modifying the kid will refer to another key, then the signature itself will not match. Therefore you don't have to include the kid in the protected header. A good example of the first part, where the information they convey is to be utilized in a trust decision, is the ACME (aka the Let's Encrypt protocol). When creating an account, and storing the key data, you want to trust the kid. We want to store kid, so we need to make sure it's valid. After the server has stored the kid and can use it to get a key, we can push messages and reference the kid in unprotected header (not done by ACME but possible). Since we're only going to verify the signature, then the kid is used a hint or reference to which kid was used for the account. If that field is tampered with, then it'll point to a nonexistent of completely different key and fail the signature the check. That means the kid itself is "the only information used in the trust decision".
There's also more theoretical scenarios that, knowing how it works you can come up with.
For example: the idea of having multiple signatures that you can pass on (exchange). A signing authority can include one signature that can be for an intermediary (server) and another for the another recipient (end-user client). This is differentiated by the kid and the server doesn't need to verify or even decode the protected header or signature. Or perhaps, the intermediary doesn't have the client's secret in order to verify a signature.
For example, a multi-recipient message (eg: chat room) could be processed by a relay/proxy and using kid in the unprotected header, pass along a reconstructed compact JWS (${protected}.${payload}.${signature}) for each recipient based on kid (or any other custom unprotected header field, like userId or endpoint).
Another example, would be a server with access to many different keys and a cleartext kid would be faster than iterating and decoded each protected field to find which one.
From one perspective, all you're doing is skipping base64url decoding the protected header for performance, but if you're going to proxy/relay the data, then you're not polluting the protected header which is meant for another recipient.