JWTs should be checked for authenticity and integrityJAVA-S1048
Always make sure to use only signed JWTs, and properly verify that a JWT's signature is valid before proceeding.
JWT
s (or, as their specification calls them, "Jots") are a standard format for storing session data on the web. They are generally used in two forms:
A plaintext JWT
is not secure and may allow an attacker with control over the client side to easily forge session information sent to the server. Meanwhile, a JWS
is more secure due to the fact that it also holds a signature derived from its contents. The signature can be generated securely, which means it is possible to check whether any tampering took place simply by comparing the included signature with the signature that would be generated with its current contents. If a mismatch occurs, the JWT can be considered invalid and rejected.
The JJWT library allows the user to directly process JWTs through methods such as JwtParser.parse(String)
, JwtParser.parseClaimsJwt(String)
or JwtParser.parsePlaintextJwt(String)
and also to check whether they are properly signed, with methods such as JwtParser.parse(String, JwtHandler<T>)
(with the right arguments) and the JWS counterparts of the other methods above.
To allow the JJWT library to properly check signatures however, a matching signing key must be set while building a JWT parser. Only when both a signing key is set and the correct methods are used can JWTs actually be verified correctly. Simply using the parse
method which takes only a single argument will not verify whether the signature is correct.
Bad Practice
Using the single argument parse
, parseClaimsJwt
and parsePlaintextJwt
methods will not check for signatures.
Jwts.parserBuilder()
.setSigningKey(signingKey)
.build()
.parse(jwt);
Jwts.parserBuilder()
.setSigningKey(signingKey)
.build()
.parseClaimsJwt(jwt);
Jwts.parserBuilder()
.setSigningKey(signingKey)
.build()
.parsePlaintextJwt(jwt);
Using the 2 argument parse
method, which accepts a JwtHandler
instance also will not work if only the onPlaintextJwt
method of the handler is overridden, as tokens with signatures will not be handled.
Jwts.parserBuilder()
.setSigningKey(signingKey).build()
.parse(plaintextJwt, new JwtHandlerAdapter<Jwt<Header, String>>() {
@Override
public Jwt<Header, String> onPlaintextJwt(Jwt<Header, String> jwt) {
return jwt; // Signed JWTs will never be handled with this code.
}
});
Recommended
Always verify the signature by using either the parseClaimsJws
and parsePlaintextJws
methods or by overriding the onPlaintextJws
or onClaimsJws
methods of JwtHandlerAdapter
.
Jwts.parserBuilder()
.setSigningKey(signingKey).build()
.parse(plaintextJwt, new JwtHandlerAdapter<Jws<String>>() {
@Override
public Jws<String> onPlaintextJws(Jws<String> jws) {
return jws;
}
});
References
- JJWT Library API Reference
- Auth0 - Critical vulnerabilities in JSON Web Token libraries
- OWASP Top Ten (2021) - Category A07 - Identification and Authentication Failures
- OWASP Top Ten (2021) - Category A01 - Broken Access Control
- CWE-304 - Missing Critical Step in Authentication