1
1
/** Provides classes for working with JWT libraries. */
2
2
3
3
import 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
+ }
17
19
}
18
20
19
21
/**
20
22
* 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.
23
27
*/
24
28
class JwtParserWithInsecureParseSink extends DataFlow:: Node {
25
29
MethodAccess insecureParseMa ;
26
30
27
31
JwtParserWithInsecureParseSink ( ) {
28
32
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
+ )
34
42
)
35
43
}
36
44
37
45
/** Gets the method access that does the insecure parsing. */
38
46
MethodAccess getParseMethodAccess ( ) { result = insecureParseMa }
39
47
}
40
48
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
58
63
}
59
64
60
65
/**
61
66
* 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`.
63
69
* `JwtHandlerAdapter`'s overrides are safe since they always throw an exception.
64
70
*/
65
71
private predicate isInsecureJwtHandler ( Expr parseHandlerExpr ) {
@@ -74,66 +80,6 @@ private predicate isInsecureJwtHandler(Expr parseHandlerExpr) {
74
80
)
75
81
}
76
82
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
-
137
83
/** The interface `io.jsonwebtoken.JwtParser`. */
138
84
private class TypeJwtParser extends Interface {
139
85
TypeJwtParser ( ) { this .hasQualifiedName ( "io.jsonwebtoken" , "JwtParser" ) }
0 commit comments