JSON Web Tokens - J Wut T?

JSON Web Token (JWT) is defined by the RFC 7519 as a compact, URL-safe means of representing claims to be transferred between two parties.  The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted. The token is composed of a header, a payload, and a signature.

What does any of that gibberish mean? Well hold onto your hats, because we are going to do a deep dive into the world of JWT.  Breaking down the token structure would be represented as follows:

{"token": "header.payload.signature"}

More or less what JWT seeks to employee is a container format.  JWT defines the structure of the information that is being sent from the client to the server side across the network and will come in two forms, serialized and deserialized.  The code snippet above shows the sections of the JWT. Now we will break down what each section is responsible for.

A header (also known as the JOSE header), it mostly used to describe the cryptographic operations applied to the JWT — signing and/or encryption. Optionally, it can also specify additional properties like media and content type of the JWT, although they are rarely used. If you want to learn more about these properties check out the specification.

The cryptographic operations in the header define whether the JWT is signed and/or encrypted, and if so what cryptographic algorithms are used. This information is provided by the alg claim with an algorithm name as a value, as in example below:

Headers = {
	"alg": "HS256"
}

The word claim that I used above comes from the JWT spec and simply means a piece of information asserted about a subject. A claim appears as a name/value pair where the name is always a string and the value can be any JSON value. In the context of a JSON object a claim is simply an object’s key.

Unsecured tokens

We learned above that the header describes the cryptographic operations applied to the JWT. However, some tokens may also be created without a signature or encryption. This usually happens when a JWT is a part of some already encrypted data structure.  It is important to keep an eye out for this, because without being secured it might be possible to change the data in the claim or payload section. Such a token is referred to as unsecured and its header should have the alg claim set to none:

{
	"alg": "none"
}

Payload

The payload is the part of the token where all interesting user data is typically found. Just like the header, the payload is a JSON object. Unlike the header, however, no claims are mandatory.  

Payload = {
	"user": "ryan",
	"iat": 1544551444,
	"exp": 1544558644
}

Serialized JWT

When JWT is serialized in order to be sent over the network the form represents a string of the following format:

[ Header ].[ Payload ].[ Signature]

A header and a payload are always present, however the signature may not be present if a JWT is unsecured. To give you an idea how it looks taken directly from the JWT.io website example page, here is a full and compact serialized forms:

Header = {
  "alg": "HS256",
  "typ": "JWT"
}
Payload = {
  "sub": "1234567890",
  "name": "ryan",
  "iat": 1516239022
}
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload), password
)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6InJ5YW4iLCJpYXQiOjE1MTYyMzkwMjJ9.-21XqDbcrGpYdWRw_Qby1FTtHgCTLTGx4_1nGlthDYg

An unsecured token will omit the signature section.  Take note of the period at the end of the following example still remains even though omitting the signature.  

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6InJ5YW4iLCJpYXQiOjE1MTYyMzkwMjJ9.

Well, that in fact looks like a bunch of gibberish.  However, the closer you look at it the easier it is to see that it is nothing but Base64 encoding, decoding and sprinkled in encryption.  

Signature

The purpose of a signature is to allow one or more parties to establish the authenticity of the token. For example an attacker may want to try and intercept the request between the client and the server side.  In attempt to tamper the user ID stored in a cookie to get access to someone else's account.  Well with JWT we can sign the header and payload to verify the authenticity of the message.  A signature, however, does not prevent other parties from reading the contents of the JWT. This is what encryption is designed to do. A signed JWT is known as JWS (JSON Web Signature) and in the compact serialized form it carries the signature that appears after the last dot.

The most common signing algorithm for JWTs is HMAC. It combines a certain payload with a secret using a cryptographic hash function (most often, SHA-256) and produces a signature that can be used to verify the message. This is so-called shared-secret signing scheme since both the party that generates the signature and the party that verifies it know the secret. And since both parties know it, both can generate a new signed message.

RSASSA is the other algorithm that is used for signing. Unlike HMAC, it allows the receiving parties to only verify the authenticity of a message, but not generate it. The algorithm is based on the public/private key scheme. The private key can be used to both create a signed message and to verify its authenticity. The public key, in contrast, can only be used to verify the authenticity of a message. This is important in one-to-many signing scenarios, like Single-Sign On, where there’s a only one producer of the message and many consumers. If, for example, a legitimate consumer turns malicious, it is impossible for it to modify a message without the other parties noticing.

Identifying JWT

In my opinion there are several great extensions for the popular tool Burp Suite. One of which is known as JWT4B (JSON Web Tokens 4 Burp).  As you can see from the screenshot below the extension will add an additional tab under the Intercept tab that will allow you to decode the JWTs on the fly.  As well will offer some potential attack methods which will cover in more depth in the next blog post.  

Need a place to test your JWT web app skills?  Check out the following page referenced on the JWT4B documentation: https://oz-web.com/jwt/ The url contains links to four pages which simulate a JWT being sent via XHR or as cookie.

Coming Soon: Attacking JWT.  Until next time keep those tokens signed!

References: