Use of the JWT 'none' algorithm

Use of the JWT none algorithm

Description

The none algorithm represents an unsigned JWT. If a service trusts such a token from an external source for authentication or authorization, an attacker may forge its contents to bypass authentication or impersonate another user.

Potential impact

  • An attacker may pass authentication with a forged token.
  • Protected user data or session information may be exposed.

Remediation

  • Verify authentication and authorization tokens with a trusted key and a server-defined allowed algorithm, such as HS256 or RS256.
  • Do not accept unsigned none tokens as proof of identity.
  • Check the issuer, audience, expiration conditions and the user's access permissions.

Examples

These excerpts use the legacy jose 1.28.2 API; use the API of a maintained version for new implementations. Replace token-here with the actual token. In the second excerpt, JWT_SECRET is the Base64 encoding of a random shared secret of at least 256 bits supplied through a trusted channel. Missing or invalid configuration and verification-error handling are omitted. HS256 uses a shared secret, not a public key.

Before

javascript
const jose = require("jose");
const { JWK, JWT } = jose;
// Accept the unsigned 'none' algorithm
const token = JWT.verify('token-here', JWK.None);

After

javascript
const jose = require("jose");
const { JWK, JWT } = jose;
const secretKey = JWK.asKey(Buffer.from(process.env.JWT_SECRET, 'base64'));
// Verify with the allowed HS256 algorithm and shared secret
const token = JWT.verify('token-here', secretKey, { algorithms: ['HS256'] });

The first excerpt explicitly accepts an unsigned token with JWK.None. The second restricts verification to HS256 with the shared secret. Use claims only after successful verification with the correct key, and separately check the claims and access permissions required by the service.

References