JWT Attacks
JWT Attacks
Payload
The payload is the part of the JWT where all the user data is added. This
data is also referred to as the ‘claims’ of the JWT. This information is
readable by anyone so it is always advised to not put any confidential
information in here. This part generally contains user information. This
information is present as a JSON object then this JSON object is encoded to
BASE64URL. We can put as many claims as we want inside a payload,
though unlike header, no claims are mandatory in a payload. The JWT with
the payload will look something like this:
{
"userId":"b07f85be-45da",
"iss": "https://provider.domain.com/",
"sub": "auth/some-hash-here",
"exp": 153452683
}
The above JWT contains userId,iss,sub,and exp. All these play a different
role as userId is the ID of the user we are storing, ‘iss’ tells us about the
issuer, ‘sub’ stands for subject, and ‘exp’ stands for expiration date.
Serialized
JWT in the serialized form represents a string of the following format:
[header].[payload].[signature]
all these three components make up the serialized JWT. We already know
what header and payload are and what they are used for.Let’s talk about
signature.
Signature
This is the third part of JWT and used to verify the authenticity of token.
BASE64URL encoded header and payload are joined together with dot(.)
and it is then hashed using the hashing algorithm defined in a header with a
secret key. This signature is then appended to header and payload using
dot(.) which forms our actual token header.payload.signature
Syntax:
HASHINGALGO( base64UrlEncode(header) + “.” +
base64UrlEncode(payload),secret)
So, all these above components together are what makes up a JWT. Now
let’s see how our actual token will look like:
JWT Example:
header:
{
"alg": "HS256",
"typ": "JWT"
}
Payload:
{
"id" : 123456789,
"name" : "Joseph"
}
Secret: GeeksForGeeks
JSON Web Token
EyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTIzNDU2Nzg5LCJuY
W1lIjoiSm9zZXBoIn0.OpOSSw7e485LOP5PrzScxHb7SR6sAOMRckfFwi4r
p7o
This feature was originally used for debugging purposes. But if not turned off
in a production environment, it would allow attackers to forge any token they
want by setting the alg field to “none”. They can then impersonate anyone
on the site by using the forged tokens.
2. HMAC algorithm
The two most common types of algorithms used for JWTs are HMAC and
RSA. With HMAC, the token would be signed with a key, then later verified
with the same key. As for RSA, the token would first be created with a private
key, then verified with the corresponding public key.
HMAC -> signed with a key, verified with the same keyRSA -> signed with a
private key, verified with the corresponding public key
It is critical that the secret key for HMAC tokens and the private key for RSA
tokens are kept a secret since they are used to sign the tokens.
Now let’s say that there is an application that was originally designed to use
RSA tokens. The tokens are signed with a private key A, which is kept a
secret from the public. Then the tokens are verified with public key B, which
is available to anyone. This is okay as long as the tokens are always treated
as RSA tokens.
Token signed with key A -> Token verified with key B (RSA scenario)
Now if the attacker changes the alg to HMAC, she might be able to create
valid tokens by signing the forged tokens with the RSA public key B.
This is because originally when the token is signed with RSA, the program
verifies it with the RSA public key B. When the signing algorithm is switched
to HMAC, the token is still verified with the RSA public key B, but this time,
the token can be signed with the same public key B (since it’s using HMAC).
Token signed with key B -> Token verified with key B (HMAC scenario)
KID manipulation
KID stands for “Key ID”. It is an optional header field in JWTs, and it allows
developers to specify the key to be used for verifying the token. The proper
usage of a KID parameter looks like this:
{
"alg": "HS256",
"typ": "JWT",
"kid": "1" // use key number 1 to verify the token
}
For example, this above injection will cause the application to return the
string “key” (since the key named “aaaaaaa” doesn’t exist in the database).
The token will then be verified with the string “key” as the secret key.
Header parameter manipulation
In addition to a key ID, JSON web token standards also provide developers
with the ability to specify keys via a URL.
1. JKU header parameter
JKU stands for “JWK Set URL”. It is an optional header field used to specify
a URL that points to a set of keys that are used to verify the token. If this field
is allowed and not properly restricted, an attacker could host their own key
file and specify that the application uses it to verify tokens.
jku URL -> file containing JWK set -> JWK used to verify the token
2. JWK header parameter
The optional JWK (JSON Web Key) header parameter allows attackers to
embed the key used to verify the token directly in the token.
Impact
· Sensitive Information Disclosure
· The authenticity of client can be compromised
· It leads Account takeover
· Attackers can access the Server Files
· they might be able to read data from the underlying SQL database
Mitigations
To prevent such attacks, applications typically use URL filtering.
Unfortunately, there are ways for attackers to bypass such filtering, including:
• Using https://trusted (for example
https://[email protected]/key.json), if the application checks for
URLs starting with trusted
• Using URL fragments with the # character
• Using the DNS naming hierarchy
• Chaining with an open redirect
• Chaining with a header Injection
• Chaining with SSRF
For this reason, it is very important for the application to whitelist permitted
hosts and have correct URL filtering in place. Beyond that, the application
must not have other vulnerabilities that an attacker might chain to bypass
URL filtering.
REFERENCE
• JWT attacks | Web Security Academy (portswigger.net)
• JSON Web Token attacks and vulnerabilities | Invicti