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
HS256orRS256. - Do not accept unsigned
nonetokens 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
const jose = require("jose");
const { JWK, JWT } = jose;
// Accept the unsigned 'none' algorithm
const token = JWT.verify('token-here', JWK.None);
After
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.