What Are JSON Web Tokens?

What Are JSON Web Tokens?

A JSON web token (JWT) is a URL-safe method of transferring claims between two parties. The JWT encodes the claims in JavaScript object notation and optionally provides space for a signature or full encryption. The JWT proposed standard has started to see wider adoption with frameworks like OAuth 2.0 and standards like OpenID connect leveraging JWTs.

In this article, we will cover:

What Are JSON Web Tokens?

A JSON web token is JSON (JavaScript object notation) with some extra structure. JWTs include a header and payload that use the JSON format. Optionally, the tokens can be encrypted or signed with a message authentication code (MAC). Signed tokens are commonly referred to as JSON web signatures (JWS) and encrypted tokens as JSON web encryption (JWE).

For the sake of verbal communication, many developers have taken to pronouncing JWT as “jot” or “jawt”. Continuing that theme, I propose the pronunciation of JWS as “jaws” and JWE as “jawa.”

The JWT is formed by concatenating the header JSON and the payload JSON with a “.” and optionally appending the signature. The whole string is then base64 URL encoded.

Example of JSON Web Tokens

JWT Example

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJMTSIsImlhdCI6MTYxOTQ3MDY4MiwiZXhwIjoxNjE5NDcxODg2LCJhdWQiOiJsb2dpY21vbml0b3IuY29tIiwic3ViIjoiTmVkIn0.mqWsk4fUZ5WAPYoY9bJHI7gD8Zwdtg9DUoCll-jXCMg

Decoded Header

{
  "typ": "JWT",
  "alg": "HS256"
}

Decoded Payload

{
  "iss": "LM",
  "iat": 1619470682,
  "exp": 1619471886,
  "aud": "logicmonitor.com",
  "sub": "Ned"
}

Signature

mqWsk4fUZ5WAPYoY9bJHI7gD8Zwdtg9DUoCll-jXCMg

When to Use JWT

A common use case is for instances where there is a need for HTTP request states to remain with the client. This is often the case with RESTful API implementations. A RESTful web service cannot keep a client state on the server and still strictly adhere to a stateless model, semantically speaking. Using a JWT allows the client to provide state information to the server for each request. This is especially helpful in secured RESTful web services that require some form of client authentication and authorization control.

Do not use a JWT when a session token will do. Generally speaking, session tokens are a well-established method of managing client access and they don’t bring any of the potential vulnerabilities mentioned below. A JWT excels in an environment where a stateless authentication method is warranted, single sign-on environments being a good example. However, there are other methods of transferring session data internally that can provide better security with comparable performance. 

Is JWT Secure?

A JSON web signature (JWS) does not inherently provide security. A service’s security or vulnerability emerges from the implementation. The most common vulnerabilities created by a JWT/JWS implementation are easily avoided but not always obvious. Some of the more common vulnerabilities arise from implementations allowing the JWT header values to drive the validation of the JWT.

If the JWT processing function blindly adheres to the algorithm type declared in the header and the “alg” header is set to “none”, the JWT would be processed as valid without any of the protection that a signature provides. This allows attacking agents to set claim values in the JWT body to whatever suits their purposes. A hardened implementation of a processing function will only allow a strict set of header values and only validate a JWT that meets those restrictions. This is a well-known exploit at this point and most modern JWT libraries and helper functions should no longer be vulnerable to it.

Even when a JWT is signed, there are still some pitfalls to be aware of. There are three basic categories of signature algorithms in common use. The “none” algorithm, as discussed above, symmetric algorithms, and asymmetric algorithms. If a mix of different algorithms is allowed by the JWT/JWS consuming service, the processing function needs to guard against a common exploit used against asynchronous JWS implementations.

Consider an example of two encryption algorithms, hash-based message authentication code (HMAC) and Rivest-Shamir-Adleman (RSA). HMAC uses a shared secret key to form and validate the signature. RSA, an asymmetric algorithm, uses a private key to form the signature and a public key to validate the signature. A system that is using the RSA algorithm would be signing with the private key and validating with the public key. If a JWT was signed using the HMAC algorithm and the public RSA key as input, then the receiving system might be fooled into attempting to use the public RSA key it has as a way to validate the signature using the HMAC algorithm. This kind of attack works when the receiving system allows the JWT header to drive the token authentication. In this case, the attacker declared the public key of the asymmetric scheme to be the shared secret key of the symmetric signature scheme. 

Best Practices When Implementing JWTs

In order to prevent these vulnerabilities, we can follow some basic best practices when implementing JWTs.

Don’t Allow the JWT Header to Drive the Authentication of the Token 

As outlined above, giving control of authentication to the JWT can create a myriad of unexpected vulnerabilities.

Avoid Weak Token Secrets

A weak secret will allow attackers to generate valid tokens.

Prevent Token Sidejacking

Protect tokens by adding a user context to tokens. A random string is provided during client authentication and kept in a hardened cookie for example.

Use Secure Token Storage

Make sure that client tokens are being stored in a secure manner, i.e. hardened cookies.

Set Reasonable Expiration Times

Even with strong signature algorithms, it is important to limit the time for which a token is valid. This way, even if a JWT falls into the wrong hands, it has an expiration date that is predictable. If a token needs to be valid for an extended period of time, consider implementing methods for token revocation.

Limit the Scope of Authorization

Issue the JWT with a very narrow scope of access. This way, even if it falls into the wrong hands it will only provide access to a reduced set of secured resources.

Require Claims That Limit the Scope of Access a Token Provides

As with the previous point, enforce those limits on the receiving end. JWTs that make claims beyond the scope limit should be rejected regardless of their signature validity.

Do Not Store Privileged Data in the JWT

A careful observer might notice that a JWT or even a JWS makes no attempt to hide the data stored in the header or the payload. This is a very important factor to consider when considering the use of a JWT. No privileged information should be stored in a JWT.

Summary

With careful consideration, the use of a JWT can be a lightweight method for managing and securing resources. Evaluate if JWT is a good fit for the problem you are trying to solve. Review the implementation plan and pay special attention to the security implications.