How JSON web tokens work

Author:
Published on:

Learn how json web tokens (jwt) work to test the their correct implementation and exploit possible vulnerabilities.

André Eichhofer

Json Web Token is a data package which contains information in JSON format which can be exchanged between parties. The Json web token can contain any kind of information, for example, user information which is utilised for session management by web applications. Json web tokens can be exchanged as cookies or any other way.

Json web tokens consist of 2 or 3 parts which are encoded:

  • header (mandatory, contains basic information, base64 encoded)
  • payload (mandatory, contains the information, base64 encoded)
  • signature (optional, hash-encoded).

The first 2 parts (header and payload) are mandatory and always part of the token. The signature is optional and used to protect the token from manipulation through man-in-the-middle-attacks, such as session hijacking.

A Json Web token may look like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 . eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ . SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
               |                                                         |                                                         |
               V                                                         V                                                         V
            Header                                                    Payload                                                  Signature
       (base64 encoded)                                            (base64 encoded)                                         (sha256 encoded)

STRUCTURE OF JSON WEB TOKENS

Json web tokens consist of a header, payload and signature (optional).

  • header.payload.signature

Header and payload are base64 encoded and can easily be decoded. The signature is hash encoded and can therefore not easily be decoded.

Header

The header contains basic information about the token. Usually, the header contains the type of the token and the hash which is used for signature.

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

In the example, the algorithm is Sha256 and the type of the token is Json Web token (JWT).

Example headers:

  • alg: specifies the encryption algorithm, mandatory for each JWT
  • typ: usually set to “JWT”
  • kid: key identifier, string that points to the location where the key is stored server side
  • jwk: used for asymmetric encryption, stores the public key
  • jku: used for asymmetric encryption, points to a url that stores the public key

Payload

The payload contains the actual information which is submitted with the token. The payload can be any kind of information. For example, the payload may contain user information for session management.

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

Signature

Signature is used to encrypt and verify the authenticity of the token. The signature is an optional part of the token. For example, if the JWT is used as an authentication token which is submitted as cookie, then the signature prevents manipulation of the JWT.

As the signature must not be decoded by unauthorised parties, it is encoded with hash value. The signature is generated like this:

  • base64 encoded header + base64 encoded payload + secret ==> hash value (= signature)

The hash value can be an arbitrary value, like MD5, SHA256, SHA384, etc. As the signature contains a secret (password) the signature cannot be decoded easily. That way, a server can verify the authenticity of session cookies. The secret is a private key (signing key), which is generated by the source code of the application. The hash value is stored in the customer database and compared with hash value submitted by the customer browser.

For example, an SHA256 encoded signature may look like this:

SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Symmetric encryption
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

JWTs can be signed using a range of different algorithms. Some of these, such as HS256 (HMAC + SHA-256) use a “symmetric” key. The algorithm is stored in the alg parameter in the header and is mandatory.

  • "alg": "hs256": Example symmetric encryption algorithm

The server uses a single key to both sign and verify the token.

Asymmetric encryption
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

Other algorithms, such as RS256 (RSA + SHA-256) use an “asymmetric” key pair. This consists of a private key, which the server uses to sign the token, and a mathematically related public key that can be used to verify the signature.

  • "alg": "rs256": Example asymmetric encryption algorithm

Lifetime

JWTs may have a certain lifetime, especially when they are used as session tokens. Session tokens should expire after a certain time to prevent Session Hijacking.

The lifetime is defined in the payload using the format "Exp":<number of seconds from 01.01.1971>

Example:

{
  "sub": "1234567890",
  "name": "John Doe",
  "Exp": 1645482432
}

GENERATING JSON WEB TOKENS

JWTs are created server side and can act as session tokens to identify a user. When the user logs in the first time, the application creates a JWT containing the user information and using the secret key, which is stored server side. Then, the application submits the JWT to the client in the response header as a cookie. Next time, the client logs in automatically using the JWT token in the GET request.

                              ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
                                              Application                
┌───────────────┐    Request  │ ┌──────────────┐      ┌──────────────┐  │
│               │               │   Username   │─────▶│ Generate JWT │   
│               ├────────────▶│ │   Password   │      └──────────────┘  │
│    Client     │               └──────────────┘              │          
│               │             │ ┌──────────────┐              ▼         │
│               ├────────────▶  │    Access    │      ┌──────────────┐   
└───────────────┘     JWT     │ │              │      │   Sign JWT   │  │
        ▲                       └──────────────┘      └──────────────┘   
        │                     └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
        │                                                     │          
        │                                                     ▼          
        │                                             ┌──────────────┐   
        │                                             │HTTP response │   
        └─────────────────────────────────────────────│              │   
                                                      │     JWT      │   
                                                      └──────────────┘   

DISCOVER JSON WEB TOKENS

JWT can be used as cookies for session management and authentication of users. When inspecting HTTP headers you can easily discover JWT in the header:

Set cookie: AuthToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Next, you can decode the first and the second part of the token with

echo eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ | base64 -d`
echo eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ | base64 -d` 

You can also use Burp Suite Decoder and the result may look like this:

{"alg":"HS256","typ":"JWT"}.{"sub":"1234567890","name":"John Doe","iat":1516239022fQ.IùJÇIHNJ(]O‡ð¤Ç‰:N²JV_iÔ,³\

As you can see, the header and payload are visible. However, the signature is hash encoded and without the secret the cookie cannot be manipulated for session hijacking.

In the next article we will examine how to exploit possible vulnerabilities in Json web tokens.

Links:

jwt.io
gchq.github.io/CyberChef