OWASP Testing Guide
  • Foreword by Eoin Keary
  • Frontispiece
  • Introduction
  • The OWASP Testing Framework
    • The Web Security Testing Framework
    • Penetration Testing Methodologies
  • Web Application Security Testing
    • Introduction and Objectives
    • Information Gathering
      • Conduct Search Engine Discovery Reconnaissance for Information Leakage (WSTG-INFO-01)
      • Fingerprint Web Server (WSTG-INFO-02)
      • Review Webserver Metafiles for Information Leakage (WSTG-INFO-03)
      • Enumerate Applications on Webserver (WSTG-INFO-04)
      • Review Webpage Content for Information Leakage (WSTG-INFO-05)
      • Identify Application Entry Points (WSTG-INFO-06)
      • Map Execution Paths Through Application (WSTG-INFO-07)
      • Fingerprint Web Application Framework (WSTG-INFO-08)
      • Fingerprint Web Application (WSTG-INFO-09)
      • Map Application Architecture (WSTG-INFO-10)
    • Configuration and Deployment Management Testing
      • Test Network Infrastructure Configuration (WSTG-CONF-01)
      • Test Application Platform Configuration (WSTG-CONF-02)
      • Test File Extensions Handling for Sensitive Information (WSTG-CONF-03)
      • Review Old Backup and Unreferenced Files for Sensitive Information (WSTG-CONF-04)
      • Enumerate Infrastructure and Application Admin Interfaces (WSTG-CONF-05)
      • Test HTTP Methods (WSTG-CONF-06)
      • Test HTTP Strict Transport Security (WSTG-CONF-07)
      • Test RIA Cross Domain Policy (WSTG-CONF-08)
      • Test File Permission (WSTG-CONF-09)
      • Test for Subdomain Takeover (WSTG-CONF-10)
      • Test Cloud Storage (WSTG-CONF-11)
      • Testing for Content Security Policy (WSTG-CONF-12)
    • Identity Management Testing
      • Test Role Definitions (WSTG-IDNT-01)
      • Test User Registration Process (WSTG-IDNT-02)
      • Test Account Provisioning Process (WSTG-IDNT-03)
      • Testing for Account Enumeration and Guessable User Account (WSTG-IDNT-04)
      • Testing for Weak or Unenforced Username Policy (WSTG-IDNT-05)
    • Authentication Testing
      • Testing for Credentials Transported over an Encrypted Channel (WSTG-ATHN-01)
      • Testing for Default Credentials (WSTG-ATHN-02)
      • Testing for Weak Lock Out Mechanism (WSTG-ATHN-03)
      • Testing for Bypassing Authentication Schema (WSTG-ATHN-04)
      • Testing for Vulnerable Remember Password (WSTG-ATHN-05)
      • Testing for Browser Cache Weaknesses (WSTG-ATHN-06)
      • Testing for Weak Password Policy (WSTG-ATHN-07)
      • Testing for Weak Security Question Answer (WSTG-ATHN-08)
      • Testing for Weak Password Change or Reset Functionalities (WSTG-ATHN-09)
      • Testing for Weaker Authentication in Alternative Channel (WSTG-ATHN-10)
      • Testing Multi-Factor Authentication (MFA) (WSTG-AUTH-11)
    • Authorization Testing
      • Testing Directory Traversal File Include (WSTG-ATHZ-01)
      • Testing for Bypassing Authorization Schema (WSTG-ATHZ-02)
      • Testing for Privilege Escalation (WSTG-ATHZ-03)
      • Testing for Insecure Direct Object References (WSTG-ATHZ-04)
      • Testing for OAuth Authorization Server Weaknesses
      • Testing for OAuth Client Weaknesses
      • Testing for OAuth Weaknesses (WSTG-ATHZ-05)
    • Session Management Testing
      • Testing for Session Management Schema (WSTG-SESS-01)
      • Testing for Cookies Attributes (WSTG-SESS-02)
      • Testing for Session Fixation (WSTG-SESS-03)
      • Testing for Exposed Session Variables (WSTG-SESS-04)
      • Testing for Cross Site Request Forgery (WSTG-SESS-05)
      • Testing for Logout Functionality (WSTG-SESS-06)
      • Testing Session Timeout (WSTG-SESS-07)
      • Testing for Session Puzzling (WSTG-SESS-08)
      • Testing for Session Hijacking (WSTG-SESS-09)
      • Testing JSON Web Tokens (WSTG-SESS-10)
    • Input Validation Testing
      • Testing for Reflected Cross Site Scripting (WSTG-INPV-01)
      • Testing for Stored Cross Site Scripting (WSTG-INPV-02)
      • Testing for HTTP Verb Tampering (WSTG-INPV-03)
      • Testing for HTTP Parameter Pollution (WSTG-INPV-04)
      • Testing for Oracle
      • Testing for MySQL
      • Testing for SQL Server
      • Testing PostgreSQL
      • Testing for MS Access
      • Testing for NoSQL Injection
      • Testing for ORM Injection
      • Testing for Client-side
      • Testing for SQL Injection (WSTG-INPV-05)
      • Testing for LDAP Injection (WSTG-INPV-06)
      • Testing for XML Injection (WSTG-INPV-07)
      • Testing for SSI Injection (WSTG-INPV-08)
      • Testing for XPath Injection (WSTG-INPV-09)
      • Testing for IMAP SMTP Injection (WSTG-INPV-10)
      • Testing for File Inclusion
      • Testing for Code Injection (WSTG-INPV-11)
      • Testing for Command Injection (WSTG-INPV-12)
      • Testing for Buffer Overflow (WSTG-INPV-13)
      • Testing for Format String Injection (WSTG-INPV-13)
      • Testing for Incubated Vulnerability (WSTG-INPV-14)
      • Testing for HTTP Splitting Smuggling (WSTG-INPV-15)
      • Testing for HTTP Incoming Requests (WSTG-INPV-16)
      • Testing for Host Header Injection (WSTG-INPV-17)
      • Testing for Server-side Template Injection (WSTG-INPV-18)
      • Testing for Server-Side Request Forgery (WSTG-INPV-19)
      • Testing for Mass Assignment (WSTG-INPV-20)
    • Testing for Error Handling
      • Testing for Improper Error Handling (WSTG-ERRH-01)
      • Testing for Stack Traces (WSTG-ERRH-02)
    • Testing for Weak Cryptography
      • Testing for Weak Transport Layer Security (WSTG-CRYP-01)
      • Testing for Padding Oracle (WSTG-CRYP-02)
      • Testing for Sensitive Information Sent via Unencrypted Channels (WSTG-CRYP-03)
      • Testing for Weak Encryption (WSTG-CRYP-04)
    • Business Logic Testing
      • Introduction to Business Logic
      • Test Business Logic Data Validation (WSTG-BUSL-01)
      • Test Ability to Forge Requests (WSTG-BUSL-02)
      • Test Integrity Checks (WSTG-BUSL-03)
      • Test for Process Timing (WSTG-BUSL-04)
      • Test Number of Times a Function Can Be Used Limits (WSTG-BUSL-05)
      • Testing for the Circumvention of Work Flows (WSTG-BUSL-06)
      • Test Defenses Against Application Misuse (WSTG-BUSL-07)
      • Test Upload of Unexpected File Types (WSTG-BUSL-08)
      • Test Upload of Malicious Files (WSTG-BUSL-09)
      • Test Payment Functionality (WSTG-BUSL-10)
    • Client-Side Testing
      • Testing for Self DOM Based Cross-Site Scripting
      • Testing for DOM-Based Cross Site Scripting (WSTG-CLNT-01)
      • Testing for JavaScript Execution (WSTG-CLNT-02)
      • Testing for HTML Injection (WSTG-CLNT-03)
      • Testing for Client-side URL Redirect (WSTG-CLNT-04)
      • Testing for CSS Injection (WSTG-CLNT-05)
      • Testing for Client-side Resource Manipulation (WSTG-CLNT-06)
      • Testing Cross Origin Resource Sharing (WSTG-CLNT-07)
      • Testing for Cross Site Flashing (WSTG-CLNT-08)
      • Testing for Clickjacking (WSTG-CLNT-09)
      • Testing WebSockets (WSTG-CLNT-10)
      • Testing Web Messaging (WSTG-CLNT-11)
      • Testing Browser Storage (WSTG-CLNT-12)
      • Testing for Cross Site Script Inclusion (WSTG-CLNT-13)
      • Testing for Reverse Tabnabbing (WSTG-CLNT-14)
    • API Testing
      • Testing GraphQL (WSTG-APIT-01)
  • Reporting
    • Reporting
    • Vulnerability Naming Schemes
  • Appendix
    • Testing Tools Resource
    • Suggested Reading
    • Fuzz Vectors
    • Encoded Injection
    • History
    • Leveraging Dev Tools
  • Testing Checklist
  • Table of Contents
  • REST Assessment Cheat Sheet
  • API Testing
Powered by GitBook
On this page
  • Summary
  • Test Objectives
  • How to Test
  • Overview
  • Analyse the Contents
  • Review Usage
  • Signature Verification
  • Weak HMAC Keys
  • HMAC vs Public Key Confusion
  • Attacker Provided Public Key
  • Related Test Cases
  • Remediation
  • Tools
  • References
  1. Web Application Security Testing
  2. Session Management Testing

Testing JSON Web Tokens (WSTG-SESS-10)

ID

WSTG-SESS-10

Summary

JSON Web Tokens (JWTs) are cryptographically signed JSON tokens, intended to share claims between systems. They are frequently used as authentication or session tokens, particularly on REST APIs.

JWTs are a common source of vulnerabilities, both in how they are in implemented in applications, and in the underlying libraries. As they are used for authentication, a vulnerability can easily result in a complete compromise of the application.

Test Objectives

  • Determine whether the JWTs expose sensitive information.

  • Determine whether the JWTs can be tampered with or modified.

How to Test

Overview

JWTs are are made up of three components:

  • The header

  • The payload (or body)

  • The signature

Each component is Base64 encoded, and they are separated by periods (.). Note that the Base64 encoding used in a JWT strips out the equals signs (=), so you may need to add these back in to decode the sections.

Analyse the Contents

Header

The header defines the type of token (typically JWT), and the algorithm used for the signature. An example decoded header is shown below:

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

There are three main types of algorithms that are used to calculate the signatures:

Algorithm
Description

HSxxx

HMAC using a secret key and SHA-xxx.

RSxxx and PSxxx

Public key signature using RSA.

ESxxx

Public key signature using ECDSA.

Payload

The payload of the JWT contains the actual data. An example payload is shown below:

{
  "username": "admininistrator",
  "is_admin": true,
  "iat": 1516239022,
  "exp": 1516242622
}

The payload is it not usually encrypted, so review it to determine whether there is any sensitive of potentially inappropriate data included within it.

Claim
Full Name
Description

iss

Issuer

The identity of the party who issued the token.

iat

Issued At

The Unix timestamp of when the token was issued.

nbf

Not Before

The Unix timestamp of earliest date that the token can be used.

exp

Expires

The Unix timestamp of when the token expires.

Signature

The signature is calculated using the algorithm defined in the JWT header, and then Base64 encoded and appended to the token. Modifying any part of the JWT should cause the signature to be invalid, and the token to be rejected by the server.

Review Usage

As well as being cryptographically secure itself, the JWT also needs to be stored and sent in a secure manner. This should include checks that:

The validity of the JWT should also be reviewed, based on the iat, nbf and exp claims, to determine that:

  • The JWT has a reasonable lifespan for the application.

  • Expired tokens are rejected by the application.

Signature Verification

One of the most serious vulnerabilities encountered with JWTs is when the application fails to validate that the signature is correct. This usually occurs when a developer uses a function such as the NodeJS jwt.decode() function, which simply decodes the body of the JWT, rather than jwt.verify(), which verifies the signature before decoding the JWT.

This can be easily tested for by modifying the body of the JWT without changing anything in the header or signature, submitting it in a request to see if the application accepts it.

The None Algorithm

As well as the public key and HMAC-based algorithms, the JWT specification also defines a signature algorithm called none. As the name suggests, this means that there is no signature for the JWT, allowing it to be modified.

This can be tested by modifying the signature algorithm (alg) in the JWT header to none, as shown in the example below:

{
        "alg": "none",
        "typ": "JWT"
}
eyJhbGciOiAibm9uZSIsICJ0eXAiOiAiSldUIn0K.eyJ1c2VybmFtZSI6ImFkbWluaW5pc3RyYXRvciIsImlzX2FkbWluIjp0cnVlLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6MTUxNjI0MjYyMn0.

Some implementations try and avoid this by explicitly blocking the use of the none algorithm. If this is done in a case-insensitive way, it may be possible to bypass by specifying an algorithm such as NoNe.

ECDSA "Psychic Signatures"

MAYCAQACAQA

Resulting in a JWT which looks something like this:

eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6InRydWUifQ.MAYCAQACAQA

Weak HMAC Keys

If the JWT is signed using a HMAC-based algorithm (such as HS256), the security of the signature is entirely reliant on the strength of the secret key used in the HMAC.

If the application is using off-the-shelf or open source software, the first step should be go investigate the code, and see whether there is default HMAC signing key that is used.

If this key can be obtained, then it is possible to create and sign arbitrary JWTs, which usually results in a complete compromise of the application.

HMAC vs Public Key Confusion

If the application uses JWTs with public key based signatures, but does not check that the algorithm is correct, this can potentially exploit this in a signature type confusion attack. In order for this to be successful, the following conditions need to be met:

  1. The application must expect the JWT to be signed with a public key based algorithm (i.e, RSxxx or ESxxx).

  2. The application must not check which algorithm the JWT is actually using for the signature.

  3. The public key used to verify the JWT must be available to the attacker.

// Verify a JWT signed using RS256
jwt.verify(token, publicKey);

// Verify a JWT signed using HS256
jwt.verify(token, secretKey);

This means that if the JWT is signed using publicKey as a secret key for the HS256 algorithm, the signature will be considered valid.

In order to exploit this issue, the public key must be obtained. The most common way this can happen is if the application re-uses the same key for both signing JWTs and as part of the TLS certificate. In this case, the key can be downloaded from the server using a command such as the following:

openssl s_client -connect example.org:443 | openssl x509 -pubkey -noout

Alternatively, the key may be available from a public file on the site at a common location such as /.well-known/jwks.json.

In order to test this, modify the contents of the JWT, and then use the previously obtained public key to sign the JWT using the HS256 algorithm. This is often difficult to perform when testing without access to the source code or implementation details, because the format of the key must be identical to the one used by the server, so issues such as empty space or CRLF encoding may result in the keys not matching.

Attacker Provided Public Key

Related Test Cases

Remediation

  • Use a secure and up to date library to handle JWTs.

  • Ensure that the signature is valid, and that it is using the expected algorithm.

  • Use a strong HMAC key or a unique private key to sign them.

  • Ensure that there is no sensitive information exposed in the payload.

  • Ensure that JWTs are securely stored and transmitted.

Tools

References

PreviousTesting for Session Hijacking (WSTG-SESS-09)NextInput Validation Testing

Last updated 2 years ago

There are also a wide range of which may be used for encrypted tokens (JWEs), although these are less common.

This JWT includes the username and administrative status of the user, as well as two standard claims (iat and exp). These claims are defined in , a brief summary of them is given in the table below:

It is always .

If it is stored in a cookie, then it should be .

The header and payload are then re-encoded with Base64, and the signature is removed (leaving the trailing period). Using the header above, and the payload listed in the section, this would give the following JWT:

A vulnerability was identified in Java version 15 to 18 where they did not correctly validate ECDSA signatures in some circumstances (, known as "psychic signatures"). If one of these vulnerable versions is used to parse a JWT using the ES256 algorithm, this can be used to completely bypass the signature verification by tampering the body and then replacing the signature with the following value:

If there isn't a default, then it may be possible to crack guess or brute-force they key. The simplest way to do this is to use the script, which simply requires the JWT and a dictionary file.

A more powerful option is to convert the JWT into a format that can be used by using the script. John can then be used to carry out much more advanced attacks against the key.

If the JWT is large, it may exceed the maximum size supported by John. This can be worked around by increasing the value of the SALT_LIMBS variable in /src/hmacSHA256_fmt_plug.c (or the equivalent file for other HMAC formats) and recompiling John, as discussed in the following .

If all of these conditions are true, then an attacker can use the public key to sign the JWT using a HMAC based algorithm (such as HS256). For example, the library uses the same function for both public key and HMAC based tokens, as shown in the example below:

The (which defines the header and signatures used by JWTs) allows the key used to sign the token to be embedded in the header. If the library used to validate the token supports this, and doesn't check the key against a list of approved keys, this allows an attacker to sign an JWT with an arbitrary key that they provide.

There are a variety of scripts that can be used to do this, such as or .

.

.

.

See the .

other algorithms
RFC 5719
sent over encrypted (HTTPS) connections
marked with appropriate attributes
CVE-2022-21449
crackjwt.py
John the Ripper
jwt2john.py
GitHub issue
Node.JS jsonwebtoken
JSON Web Signature (JWS) standard
jwk-node-jose.py
jwt_tool
Testing for Sensitive Information Sent via Unencrypted Channels
Testing for Cookie Attributes
Testing Browser Storage
OWASP JSON Web Tokens Cheat Sheet
John the Ripper
jwt2john
jwt-cracker
JSON Web Tokens Burp Extension
ZAP JWT Add-on
RFC 7515 JSON Web Signature (JWS)
RFC 7519 JSON Web Token (JWT)
OWASP JSON Web Token Cheat Sheet
payload