JSON Web Token (JWT) is a JSON encoded representation of a claim(s) that can be transferred between two parties. The claim is digitally signed by the issuer of the token, and the party receiving this token can later use this digital signature to prove the ownership on the claim.
JWTs can be broken down into three parts: header, payload, and signature. Each part is separated from the other by dot (.), and will follow the below structure:
Header.Payload.Signature
View The New 2021 OWASP Top 10
The information contained in the header describes the algorithm used to generate the signature. The decoded version of the header from the above example looks like:
{
"alg": "HS256",
"typ": "JWT"
}
HS256 is the hashing algorithm HMAC SHA-256 used to generate the signature in the above example.
All the claims within JWT authentication are stored in this part. Claims are used to provide authentication to the party receiving the token. For example, a server can set a claim saying ‘isAdmin: true’ and issue it to an administrative user upon successfully logging into the application. The admin user can now send this token in every consequent request he/she sends to the server to prove their identity.
The decoded version of the payload from the JWT example provided above looks like:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
The ‘name’ field is used to identify the user to whom the token was issued to. The ‘sub’ and ‘iat’ are examples of registered claims and are short for ‘subject’ and ‘issued at’.
The signature part of a JWT is derived from the header and payload fields. The steps involved in creating this signature are described below:
1. Combine the base64url encoded representations of header and payload with a dot (.)
base64UrlEncode(header) + “.” + base64UrlEncode(payload)
2. Hash the above data with a secret-key only known to the server issuing the token. The hashing algorithm is the one described inside the header.
hash_value = hash([base64UrlEncode(header) + “.” + base64UrlEncode(payload)], secret-key)
3. Base64Url encode the hash value obtained from the step above
Signature = base64UrlEncode(hash_value)
Because the ‘secret-key’ is only known to the server, only it can issue new tokens with a valid signature. Users can not forge tokens as producing a valid Signature for the token requires the knowledge of the ‘secret-key’.
JWT find their applications in various authentication mechanisms. These are typically passed in the Authorization header when a user submits a request to the client.
eg:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0I joxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
GUIDE TO APPSEC FOR SAAS COMPANIES
Tampering with the Signing Algorithm:
‘none’ algorithm: JWT supports the usage of ‘none’ algorithm for use-cases where the integrity of the claim within JWT is already verified by other means. This algorithm allows the server to issue a JWT without a signature. The content within a token issued with a ‘none’ algorithm will look like the following:
{"alg":"none","typ": "JWT"}.{"sub":"1234567890","name":"John Doe","iat": 1516239022}.
It is worth noting that the ‘none’ algorithm along with ‘HMAC SHA-256 (HS256)’ are the only two algorithms that are mandatory to implemented according to the JWT standard.(1)
Attackers can use this feature to set the algorithm in their token to ‘none’ and provide an empty signature to fool the server into accepting it as a valid token. However, most of the modern implementations now have an added security check that rejects tokens set with ‘none’ algorithm when a secret-key was used to issue them.
RS256 to HS256: JWT supports the usage of asymmetric signing algorithms such as RS256 which uses a private key to sign the token and a public key to verify the signature. The private key is only known to the server and the public key is accessible to everyone.
The use of asymmetric signing algorithms is useful in situations where 3rd party clients need to verify the validity of a JWT not issued by them. A server signing JWTs with a symmetric algorithm such as HS256 will have to share the secret-key with all the 3rd party clients that want verify the token. This increases the risk of secret-key being disclosed.
In insecure implementations where the server trusts the data inside the header of a JWT and doesn’t validate the algorithm it used to issue a token, attackers can change the algorithm from ‘RS256’ to ‘HS256’ and use the ‘public’ key to generate a HMAC signature for the token. The server will now treat this token as one generated with ‘HS256’ algorithm and use its public key to decode and verify it.
Brute-Forcing HS256:
JWTs signed with HS256 algorithm could be vulnerable to secret-key disclosure. that usually happens through brute-force attacks, especially for weak keys. Since a client does not need to interact with the server to check the validity of secret-key after a token is issued by the server, attackers can conduct offline brute-force attacks against the token by using wordlists of possible secret-keys.
It is recommended to use sufficiently long (256 bit) keys to safeguard against these attacks.
Sensitive Information disclosure:
All the information inside the payload is stored in plain text. It is important not to leak sensitive information such as internal IP addresses through the tokens.
Attacks against JWT arise from bad implementations and using outdated libraries. To benefit from the security features JWT offers, follow the best practices for implementing them, only use up-to-date and secure libraries and choose the right algorithm for your use-case.
Here is a short video of how and why JWT is created, and where it is used:
301 Moodie Dr. Unit 108
Ottawa ON K2H 9C4