Share some knowledge, skills and others — security research, pentesting notes and more.

View on GitHub
30 September 2018

Json Web Tokens

by allencharp

What is JWT

JSON Web Token (JWT, RFC 7519) is a compact, URL-safe token format used to transmit claims between parties. First, take a look at this JWT debugger.

Simply put, a JWT is a string with the following format:

header.payload.signature

Each part is base64url encoded (base64 with - and _ instead of + and /, and no padding =), so the token can safely appear in URLs and HTTP headers.

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

typ is of course JWT, and the signing algorithm here is HS256 (HMAC-SHA256). The header tells the verifier how the token was signed — which is exactly why the algorithm must be trusted explicitly (see attacks below).

Payload

The payload component is the data stored in the JWT. There are some optional registered claims, such as:

{
  "userId": "1101001",
  "name": "Allen",
  "exp": 1547078400
}

Note: exp is a NumericDate (Unix timestamp), not a date string. An expired token must be rejected.

Signature

The JWT signature is computed roughly like this:

data = base64urlEncode( header ) + '.' + base64urlEncode( payload )
hashedData = hash( data, secret )
signature = base64urlEncode( hashedData )

The signature proves that the token was created by someone who knows the secret (HS256) or owns the private key (RS256).

How does JWT protect data

Most importantly, JWT is not a way to encrypt the data — it is a way to prove the data was created by an authentic source, so the data can be easily decoded and read.

JWT does not guarantee any security for sensitive data. Do not save sensitive data in a JWT.

Common JWT Attacks

1. alg: none

Some libraries accept a token whose header says "alg": "none" and skip signature verification entirely. An attacker can forge a token with arbitrary claims:

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

Fix: always verify the signature; reject none and enforce an explicit algorithm allowlist.

2. Algorithm confusion (RS256 → HS256)

The server verifies RS256 tokens with the public key, but HS256 tokens with a shared secret. If the server blindly trusts the alg header, an attacker can send an HS256 token signed with the server’s public key — the server treats the public key as the HMAC secret and accepts the forgery.

Fix: pin the expected algorithm server-side; never derive it from the token header.

3. Weak secret brute force

For HS256, the HMAC secret is shared. If it is weak (a common word), offline brute force with a wordlist is trivial once a valid token is obtained.

Fix: use a high-entropy random secret, rotate it regularly.

Secure Usage Checklist

Summary

JWT is a signing mechanism, not encryption. The security of a JWT-based system depends on strict signature verification, an explicit algorithm allowlist, and keeping secrets high-entropy. Most real-world JWT vulnerabilities come from implementations that trust attacker-controlled alg values.

tags: web-security - jwt - authentication