Application SecurityCode Fighters

JSON WEB Tokens: Tips and procedures for secure implementation

JWT (JSON WEB Tokens) is an open standard, documented by RFC-7519, that defines how to transmit and store JSON objects in a simple, compact and secure way between different applications. It is widely used to validate services in Web Services, as the data contained in a token can be validated at any time since it is digitally signed. In this article, we’ll show some examples of their usage and review common errors in their implementation, considering the main types of attacks, and provide some recommendations on how to avoid them.

You can also listen to the audio version of this article:

Before going into details about Tips and Attacks for a Secure Implementation in JSON WEB Tokens, it is important to understand that JWT is a JSON framework. The specification on how to encrypt or digitally sign a JWT is known as Javascript Object Signing and Encryption (JOSE). It consists of the following components:

JWT: JSON Web Token, the token itself;
JWE: JSON Web Encryption, encryption for token signing;
JWA: JSON Web Algorithms, about token signing algorithms;
JWK: JSON Web Keys, the keys for signing;
JWS: JSON Web Signature, about the token signature.

Structure

Its structure is composed of 3 parts: Header, Payload and Signature; They are separated by a dot (.) and each part is individually encoded in Base64Url.

Header

The header specifies the algorithm that was used to generate the JWT signature and optionally other token properties. The main types of supported cryptographic algorithms are:

• HMAC
• RSA

Payload

The Payload is a JSON object with the claims of the treated entity, in this part, authenticated user data is usually stored when used in authentication processes.

These claims can be of 3 types, such as: Reserved claims, Public claims and Private claims.

Reserved claims: Non-mandatory (but recommended) attributes that are used in token validation by API security protocols, such as:

sub (subject) = Entity to whom the token belongs, typically the user ID;
iss (issuer) = Token issuer;
exp (expiration) = Timestamp of token expiration;
iat (issued at) = Timestamp of token creation;
aud (audience) = Recipient of the token, represents the application that will use it.

Generally, the most used attributes are: sub, iss e exp.

Public claims: These can be set at will by those using JWTs. But to avoid collisions, they must be defined in the IANA JSON Web Token Registry.

Private claims: Custom attributes specially defined to share information between specific applications that agree to use them.

Signature

Signature is the joining of hashes generated from Header and Payload using base64UrlEncode, with a secret key or RSA certificate.

This signature is used to guarantee the integrity of the token, in this case, if it was modified and if it was really generated by you.

This prevents man-in-the-middle attacks, where an attacker could intercept the request and modify its content with false information. If the payload is changed, the final hash will not be valid as it was not signed with the secret key and the information will be rejected.

The end result is a token with three sections (header, payload, signature) separated by “.”

Some of the main implementation errors

. Store sensitive information on payload

When analyzing a JWT (JSON WEB Tokens), we can forget that the information contained in it should be considered as public, since anyone who gains access to a token can easily verify the information contained in the payload. To verify this, take any JWT token and put it in the jwt.io debugger, even if it is not possible to validate it, it will be possible to identify and analyze all the information contained in it.

Remember to always put only what is necessary and never put information such as passwords, Personally identifiable information (PII), or other sensitive information, which in addition to increasing the size of the token, can end up causing a security breach.

 . Do not set an expiration time

From the very first implementation, it is extremely important to define an expiration time in the JWT. As all services that use the token to validate that the user is authenticated trust the information contained in it, if this token does not have an expiration time, anyone who obtains it, under certain circumstances will be authenticated forever. When you set an expiration time, you decrease the chance that a valid token can be reused and allow a malicious person to impersonate another user.

. Use a very high expiration time

It is also not advisable to set an expiry time too high, as the idea is exactly to prevent valid tokens from circulating among malicious people. It is always worth thinking about the needs of your system, as a one-week expiration time is often unnecessary. A time that is generally recommended as the default is 15 minutes.

As an alternative to “logging out” the user from the application, refresh tokens can be used to generate new JWT authentication tokens. Refresh tokens are sent to the authentication service when your JWT has expired or is about to expire and is validated against the database, giving the possibility to disable a refresh token. It’s worth studying techniques like this one further to ensure a good user experience.

. Use a weak signature algorithm

The standard algorithm used to sign a JWT (JSON WEB Tokens) is HS256, in which a key is used, as if it were a password, both to generate the tokens and to validate them (in other words, it is a symmetric algorithm). This works fine, however, as several services may contain this key just to validate the JWT (imagine you have your authentication service and an order management service, both would have the same key in your settings) the chances that it will leak can be bigger, and if someone gets access to this key, can easily generate valid authentication tokens, consequently generating a lot of risks.

A person who has the key can modify payload values ​​to impersonate other users, or even escalate privileges if the token is used for authorization.

An alternative is to use an asymmetric algorithm, that is, an algorithm in which a private key is used to generate the tokens and a public key is used to validate it. With algorithms such as RSA or ECDSA, only your authentication service will have the key needed to generate the tokens, while the other services will only have the key to validate them, thus minimizing security risks.

. Do not use other JWT reserved claims

It is not only the expiration time that can be configured in the JWT, some other claims are also reserved and supported by the libraries and can be used to further increase the security of your tokens. For example, the claim “aud” that allows specifying which services must accept the generated token, or the “iss” that defines which service generated the token. To learn more about claims and their functionalities it is recommended to read the JWT RFC.

Main Exploration Techniques JSON WEB Tokens

. None Algorithm

The none algorithm is a curious addition to JWT (JSON WEB Tokens), originally present in the Header section to express that the token does not have a signature, has now been used to exploit one of the most well-known vulnerabilities in JWT.

Unfortunately, some implementations and vulnerable libraries treated tokens defined with the “none” algorithm as a valid token with a verified signature. The result? Anyone can create their own “signed” tokens with any payload they want, allowing arbitrary account access and privilege escalation on some systems.

To test this vulnerability it is necessary to modify the token header, replacing the content of the algorithm attribute to “none”, as shown below:

Headers = {
  “alg”: “none”
}

Then, just encode again on base64Url of each part of the token and concatenate them, with the exception of the signature part, which should be omitted, but the last point must be present, resulting in something like the following example:

eyJhbGciOiJub25lIn0.eyJuYW1lIjoiYWRtaW4ifQ.

To avoid this weakness, be sure to use a JWT library that is not exposed to this vulnerability.

Finally, during token validation, explicitly request that the expected algorithm be used.

. Changing the algorithm from “RS256” to “HS256”

We know that JSON WEB tokens can be signed by symmetric and asymmetric algorithms, and the algorithm used in the “Header” can be consulted; In cases of asymmetric algorithms such as RS256, comparison with a public key is necessary, as it has already been signed using a private key, unlike asymmetric algorithms such as HS256, which uses only a secret key .

With this in mind, some vulnerable implementations that use an asymmetric algorithm can be exploited by performing the substitution to a symmetric algorithm, being able to sign new tokens with the public key, which, being public, can often be obtained by the attacker. This will cause it to be compared to itself in the validation process, and since HS256 only uses one secret/key it will match if vulnerable.

. Use an invalid signature

Due to implementation errors, it is possible that the token signature is never verified when it arrives at the application. In this way, an attacker can simply bypass the security mechanism by providing an invalid signature.

. Brute Force on weak HMAC keys

If the application is using a weak HMAC key (algs HS256/HS384/HS512), which, as it is symmetrical, uses only one key, there is the possibility of using brute force on the key to identify it and can thus be used to sign a new token.

HMAC JWT cracking is therefore entirely offline and can be performed on a large scale by an attacker, in other words the token can be tested for valid passwords without having to send it back to the application verify it.

There are numerous tools to crack JWT, some of them are jwt-tool and jwt-cracker.

If you have a strong GPU for breaking hashes, it can be used with the hashcat tool, testing an incredibly high number of parallel tasks. The command below demonstrates the use of hashcat using a dictionary of possible secret keys:

. Kid Manipulation

As described in RFC the kid (Key identifier) ​​is one of the optional claims that the developer can include in the header, it is commonly used when you have several keys to sign the tokens and need to look for the right one to verify the signature.

Because it is user-controlled, an attacker can manipulate its value in order to exploit vulnerabilities such as:

1 – Directory traversal

As “kid” is often used to return a system key file, if it is not sanitized before use, it can lead to a Directory Traversal attack. When this is the case, the attacker can specify any file on the system as the key to be used to verify the token.

In the example above, the attacker will force the application to use a publicly available file as the key and sign an HMAC token using that file.

2 – SQL Injection

Another possible attack to be performed on the “kid” is the SQL Injection attack, the attacker can inject SQL code to return any value they want.

For example, the injection below will cause the application to return the string “secret_key” (since the string called “test” does not exist in the database). The token will then be verified with the string “secret_key” as the secret key.

What can we conclude about security in JSON Web Tokens?

JSON Web Token is a secure way to transfer data between two parties, as long as it is correctly implemented and used, having its pros and cons, each type of implementation must take into account the benefits and risks of its use.

One of the scenarios that the use of JWT is not recommended is for the management of user sessions, given its size, impossibility of being invalidated and among other risks that this implementation may entail, but JWTs can still be used together with session tokens, each with its own purpose.

To conclude, there are several good practices for using JWT, among the main ones are:

  • Restrict accepted algorithms to the one you want to use;
  • Check all tokens before processing payload data;
  • Always sanitize data that can be manipulated by the user;
  • Restrict URLs of any JWKS/X509 certificates;
  • Use the strongest signing process for which you can afford CPU time;
  • Use asymmetric keys if tokens are used on more than one server;
  • Use strong keys;
  • Always try to use the most recent version of the JWT library that you choose, and perform a search for possible CVE’s to verify that the version used has no publicly known vulnerabilities.

References

About author

Articles

Information Security professional, João Ciconet works as a Pentester at Conviso with a focus on web application analysis. He has published articles and CVE's in this area, and is passionate about finding vulnerabilities and understanding applications in depth.
Related posts
Application Security

The Importance of Supply Chain to Application Security

When we think about software development, we usually think about complex technical concepts…
Read more
Application Security

What is WAAP (Web Application and API Protection)

Welcome to the world of Web Application and API Protection (WAAP), an advanced security approach…
Read more
Application Security

The challenges in application security in the use of artificial intelligence by developers

As artificial intelligence (AI) becomes more and more present in our daily lives, it has become…
Read more

Deixe um comentário