11/** Provides classes for working with JWT libraries. */
22
33import java
4- import semmle.code.java.dataflow.DataFlow
5- import semmle.code.java.dataflow.ExternalFlow
6-
7- /**
8- * An expr that is a (sub-type of) `JwtParser` for which a signing key has been set
9- */
10- class JwtParserWithSigningKeyExpr extends Expr {
11- MethodAccess signingMa ;
12-
13- JwtParserWithSigningKeyExpr ( ) { isSigningKeySetter ( this , signingMa ) }
14-
15- /** Gets the method access that sets the signing key for this parser. */
16- MethodAccess getSigningMethodAccess ( ) { result = signingMa }
4+ private import semmle.code.java.dataflow.ExternalFlow
5+ private import semmle.code.java.dataflow.DataFlow
6+
7+ /** A method access that assigns signing keys to a JWT parser. */
8+ class JwtParserWithInsecureParseSource extends DataFlow:: Node {
9+ JwtParserWithInsecureParseSource ( ) {
10+ exists ( MethodAccess ma , Method m |
11+ m .getDeclaringType ( ) .getASupertype * ( ) instanceof TypeJwtParser or
12+ m .getDeclaringType ( ) .getASupertype * ( ) instanceof TypeJwtParserBuilder
13+ |
14+ this .asExpr ( ) = ma and
15+ ma .getMethod ( ) = m and
16+ m .hasName ( [ "setSigningKey" , "setSigningKeyResolver" ] )
17+ )
18+ }
1719}
1820
1921/**
2022 * The qualifier of an insecure parsing method.
21- * That is, either the qualifier of a call to a `parse(token)`, `parseClaimsJwt(token)` or `parsePlaintextJwt(token)` method or
22- * the qualifier of a call to a `parse(token, handler)` method where the `handler` is considered insecure.
23+ * That is, either the qualifier of a call to the `parse(token)`,
24+ * `parseClaimsJwt(token)` or `parsePlaintextJwt(token)` methods or
25+ * the qualifier of a call to a `parse(token, handler)` method
26+ * where the `handler` is considered insecure.
2327 */
2428class JwtParserWithInsecureParseSink extends DataFlow:: Node {
2529 MethodAccess insecureParseMa ;
2630
2731 JwtParserWithInsecureParseSink ( ) {
2832 insecureParseMa .getQualifier ( ) = this .asExpr ( ) and
29- (
30- sinkNode ( this , "jwt-insecure-parse" )
31- or
32- sinkNode ( this , "jwt-insecure-parse-handler" ) and
33- isInsecureJwtHandler ( insecureParseMa .getArgument ( 1 ) )
33+ exists ( Method m |
34+ insecureParseMa .getMethod ( ) = m and
35+ m .getDeclaringType ( ) .getASupertype * ( ) instanceof TypeJwtParser and
36+ m .hasName ( [ "parse" , "parseClaimsJwt" , "parsePlaintextJwt" ] ) and
37+ (
38+ m .getNumberOfParameters ( ) = 1
39+ or
40+ isInsecureJwtHandler ( insecureParseMa .getArgument ( 1 ) )
41+ )
3442 )
3543 }
3644
3745 /** Gets the method access that does the insecure parsing. */
3846 MethodAccess getParseMethodAccess ( ) { result = insecureParseMa }
3947}
4048
41- /**
42- * Holds if `signingMa` directly or indirectly sets a signing key for `expr`, which is a `JwtParser`.
43- * The `setSigningKey` and `setSigningKeyResolver` methods set a signing key for a `JwtParser`.
44- *
45- * Directly means code like this (the signing key is set directly on a `JwtParser`):
46- * ```java
47- * Jwts.parser().setSigningKey(key).parse(token);
48- * ```
49- *
50- * Indirectly means code like this (the signing key is set on a `JwtParserBuilder` indirectly setting the key of `JwtParser` that is created by the call to `build`):
51- * ```java
52- * Jwts.parserBuilder().setSigningKey(key).build().parse(token);
53- * ```
54- */
55- private predicate isSigningKeySetter ( Expr expr , MethodAccess signingMa ) {
56- any ( SigningToInsecureMethodAccessDataFlow s )
57- .hasFlow ( DataFlow:: exprNode ( signingMa ) , DataFlow:: exprNode ( expr ) )
49+ /** A set of additional taint steps to consider when taint tracking JWT related data flows. */
50+ class JwtParserWithInsecureParseAdditionalTaintStep extends Unit {
51+ predicate step ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
52+ jwtParserStep ( node1 .asExpr ( ) , node2 .asExpr ( ) )
53+ }
54+ }
55+
56+ /** Models the builder style of `JwtParser` and `JwtParserBuilder`. */
57+ private predicate jwtParserStep ( Expr parser , MethodAccess ma ) {
58+ (
59+ parser .getType ( ) .( RefType ) .getASourceSupertype * ( ) instanceof TypeJwtParser or
60+ parser .getType ( ) .( RefType ) .getASourceSupertype * ( ) instanceof TypeJwtParserBuilder
61+ ) and
62+ ma .getQualifier ( ) = parser
5863}
5964
6065/**
6166 * Holds if `parseHandlerExpr` is an insecure `JwtHandler`.
62- * That is, it overrides a method from `JwtHandlerOnJwtMethod` and the override is not defined on `JwtHandlerAdapter`.
67+ * That is, it overrides a method from `JwtHandlerOnJwtMethod` and
68+ * the override is not defined on `JwtHandlerAdapter`.
6369 * `JwtHandlerAdapter`'s overrides are safe since they always throw an exception.
6470 */
6571private predicate isInsecureJwtHandler ( Expr parseHandlerExpr ) {
@@ -74,66 +80,6 @@ private predicate isInsecureJwtHandler(Expr parseHandlerExpr) {
7480 )
7581}
7682
77- /** CSV source models representing methods that assign signing keys to a JWT parser. */
78- private class SigningKeySourceModel extends SourceModelCsv {
79- override predicate row ( string row ) {
80- row =
81- [
82- "io.jsonwebtoken;JwtParser;true;setSigningKey;;;ReturnValue;jwt-signing-key" ,
83- "io.jsonwebtoken;JwtParser;true;setSigningKeyResolver;;;ReturnValue;jwt-signing-key" ,
84- "io.jsonwebtoken;JwtParserBuilder;true;setSigningKey;;;ReturnValue;jwt-signing-key" ,
85- "io.jsonwebtoken;JwtParserBuilder;true;setSigningKeyResolver;;;ReturnValue;jwt-signing-key"
86- ]
87- }
88- }
89-
90- /** CSV sink models representing qualifiers of methods that parse a JWT insecurely. */
91- private class InsecureJwtParseSinkModel extends SinkModelCsv {
92- override predicate row ( string row ) {
93- row =
94- [
95- "io.jsonwebtoken;JwtParser;true;parse;(String);;Argument[-1];jwt-insecure-parse" ,
96- "io.jsonwebtoken;JwtParser;true;parseClaimsJwt;;;Argument[-1];jwt-insecure-parse" ,
97- "io.jsonwebtoken;JwtParser;true;parsePlaintextJwt;;;Argument[-1];jwt-insecure-parse"
98- ]
99- }
100- }
101-
102- /** CSV sink models representing qualifiers of methods that insecurely parse a JWT with a handler */
103- private class InsecureJwtParseHandlerSinkModel extends SinkModelCsv {
104- override predicate row ( string row ) {
105- row =
106- [
107- "io.jsonwebtoken;JwtParser;true;parse;(String,JwtHandler);;Argument[-1];jwt-insecure-parse-handler"
108- ]
109- }
110- }
111-
112- /** Models the builder style of `JwtParser` and `JwtParserBuilder`. */
113- private predicate jwtParserStep ( Expr parser , MethodAccess ma ) {
114- (
115- parser .getType ( ) .( RefType ) .getASourceSupertype * ( ) instanceof TypeJwtParser or
116- parser .getType ( ) .( RefType ) .getASourceSupertype * ( ) instanceof TypeJwtParserBuilder
117- ) and
118- ma .getQualifier ( ) = parser
119- }
120-
121- /**
122- * Models flow from signing keys assignements to qualifiers of JWT insecure parsers.
123- * This is used to determine whether a `JwtParser` has a signing key set.
124- */
125- private class SigningToInsecureMethodAccessDataFlow extends DataFlow:: Configuration {
126- SigningToInsecureMethodAccessDataFlow ( ) { this = "SigningToExprDataFlow" }
127-
128- override predicate isSource ( DataFlow:: Node source ) { sourceNode ( source , "jwt-signing-key" ) }
129-
130- override predicate isSink ( DataFlow:: Node sink ) { sink instanceof JwtParserWithInsecureParseSink }
131-
132- override predicate isAdditionalFlowStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
133- jwtParserStep ( node1 .asExpr ( ) , node2 .asExpr ( ) )
134- }
135- }
136-
13783/** The interface `io.jsonwebtoken.JwtParser`. */
13884private class TypeJwtParser extends Interface {
13985 TypeJwtParser ( ) { this .hasQualifiedName ( "io.jsonwebtoken" , "JwtParser" ) }
0 commit comments