diff --git a/java/ql/src/experimental/Security/CWE/CWE-347/MissingJWTSignatureCheck.java b/java/ql/src/experimental/Security/CWE/CWE-347/MissingJWTSignatureCheck.java new file mode 100644 index 00000000000..1760b4d6097 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-347/MissingJWTSignatureCheck.java @@ -0,0 +1,34 @@ +public void badJwt(String token) { + Jwts.parserBuilder() + .setSigningKey("someBase64EncodedKey").build() + .parse(token); // BAD: Does not verify the signature +} + +public void badJwtHandler(String token) { + Jwts.parserBuilder() + .setSigningKey("someBase64EncodedKey").build() + .parse(plaintextJwt, new JwtHandlerAdapter>() { + @Override + public Jwt onPlaintextJwt(Jwt jwt) { + return jwt; + } + }); // BAD: The handler is called on an unverified JWT +} + +public void goodJwt(String token) { + Jwts.parserBuilder() + .setSigningKey("someBase64EncodedKey").build() + .parseClaimsJws(token) // GOOD: Verify the signature + .getBody(); +} + +public void goodJwtHandler(String token) { + Jwts.parserBuilder() + .setSigningKey("someBase64EncodedKey").build() + .parse(plaintextJwt, new JwtHandlerAdapter>() { + @Override + public Jws onPlaintextJws(Jws jws) { + return jws; + } + }); // GOOD: The handler is called on a verified JWS +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-347/MissingJWTSignatureCheck.qhelp b/java/ql/src/experimental/Security/CWE/CWE-347/MissingJWTSignatureCheck.qhelp new file mode 100644 index 00000000000..4a5398f1ac5 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-347/MissingJWTSignatureCheck.qhelp @@ -0,0 +1,39 @@ + + + + +

A JWT consists of three parts: header, payload, and signature. +The io.jsonwebtoken.jjwt library is one of many libraries used for working with JWTs. +It offers different methods for parsing tokens like parse, parseClaimsJws, and parsePlaintextJws. +The last two correctly verify that the JWT is properly signed. +This is done by computing the signature of the combination of header and payload and +comparing the locally computed signature with the signature part of the JWT. +

+

+Therefore it is necessary to provide the JwtParser with a key that is used for signature validation. +Unfortunately the parse method accepts a JWT whose signature is empty although a signing key has been set for the parser. +This means that an attacker can create arbitrary JWTs that will be accepted. +

+
+ + +

Always verify the signature by using either the parseClaimsJws and parsePlaintextJws methods or +by overriding the onPlaintextJws or onClaimsJws of JwtHandlerAdapter. +

+ +
+ + +

The following example shows four cases where a signing key is set for a parser. +In the first bad case the parse method is used which will not validate the signature. +The second bad case uses a JwtHandlerAdapter where the onPlaintextJwt method is overriden so it will not validate the signature. +The third and fourth good cases use parseClaimsJws method or override the onPlaintextJws method. +

+ + + +
+ +
  • zofrex: How I Found An alg=none JWT Vulnerability in the NHS Contact Tracing App.
  • +
    +
    \ No newline at end of file