Repository navigation
Expand file tree
/
Copy pathJWT.qll
More file actions
131 lines (116 loc) · 4.63 KB
/
Copy pathJWT.qll
File metadata and controls
131 lines (116 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/** Provides classes for working with JSON Web Token (JWT) libraries. */
overlay[local?]
module;
import java
private import semmle.code.java.dataflow.FlowSinks
private import semmle.code.java.dataflow.FlowSources
/** A method access that assigns signing keys to a JWT parser. */
class JwtParserWithInsecureParseSource extends ApiSourceNode {
JwtParserWithInsecureParseSource() {
exists(MethodCall ma, Method m |
m.getDeclaringType().getAnAncestor() instanceof TypeJwtParser or
m.getDeclaringType().getAnAncestor() instanceof TypeJwtParserBuilder
|
this.asExpr() = ma and
ma.getMethod() = m and
m.hasName(["setSigningKey", "setSigningKeyResolver"])
)
}
}
/**
* The qualifier of an insecure parsing method.
* That is, either the qualifier of a call to the `parse(token)`,
* `parseClaimsJwt(token)` or `parsePlaintextJwt(token)` methods or
* the qualifier of a call to a `parse(token, handler)` method
* where the `handler` is considered insecure.
*/
class JwtParserWithInsecureParseSink extends ApiSinkNode {
MethodCall insecureParseMa;
JwtParserWithInsecureParseSink() {
insecureParseMa.getQualifier() = this.asExpr() and
exists(Method m |
insecureParseMa.getMethod() = m and
m.getDeclaringType().getAnAncestor() instanceof TypeJwtParser and
m.hasName(["parse", "parseClaimsJwt", "parsePlaintextJwt"]) and
(
m.getNumberOfParameters() = 1
or
isInsecureJwtHandler(insecureParseMa.getArgument(1))
)
)
}
/** Gets the method access that does the insecure parsing. */
MethodCall getParseMethodCall() { result = insecureParseMa }
}
/**
* A unit class for adding additional flow steps.
*
* Extend this class to add additional flow steps that should apply to the `MissingJwtSignatureCheckConf`.
*/
class JwtParserWithInsecureParseAdditionalFlowStep extends Unit {
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
}
/** A set of additional flow steps to consider when working with JWT parsing related data flows. */
private class DefaultJwtParserWithInsecureParseAdditionalFlowStep extends JwtParserWithInsecureParseAdditionalFlowStep
{
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
jwtParserStep(node1.asExpr(), node2.asExpr())
}
}
/** Models the builder style of `JwtParser` and `JwtParserBuilder`. */
private predicate jwtParserStep(Expr parser, MethodCall ma) {
(
parser.getType().(RefType).getASourceSupertype*() instanceof TypeJwtParser or
parser.getType().(RefType).getASourceSupertype*() instanceof TypeJwtParserBuilder
) and
ma.getQualifier() = parser
}
/**
* Holds if `parseHandlerExpr` is an insecure `JwtHandler`.
* That is, it overrides a method from `JwtHandlerOnJwtMethod` and
* the override is not defined on `JwtHandlerAdapter`.
* `JwtHandlerAdapter`'s overrides are safe since they always throw an exception.
*/
private predicate isInsecureJwtHandler(Expr parseHandlerExpr) {
exists(RefType t |
parseHandlerExpr.getType() = t and
t.getASourceSupertype*() instanceof TypeJwtHandler and
exists(Method m |
m = t.getAMethod() and
m.getASourceOverriddenMethod+() instanceof JwtHandlerOnJwtMethod and
not m.getSourceDeclaration() instanceof JwtHandlerAdapterOnJwtMethod
)
)
}
/** The interface `io.jsonwebtoken.JwtParser`. */
private class TypeJwtParser extends Interface {
TypeJwtParser() { this.hasQualifiedName("io.jsonwebtoken", "JwtParser") }
}
/** The interface `io.jsonwebtoken.JwtParserBuilder`. */
private class TypeJwtParserBuilder extends Interface {
TypeJwtParserBuilder() { this.hasQualifiedName("io.jsonwebtoken", "JwtParserBuilder") }
}
/** The interface `io.jsonwebtoken.JwtHandler`. */
private class TypeJwtHandler extends Interface {
TypeJwtHandler() { this.hasQualifiedName("io.jsonwebtoken", "JwtHandler") }
}
/** The class `io.jsonwebtoken.JwtHandlerAdapter`. */
private class TypeJwtHandlerAdapter extends Class {
TypeJwtHandlerAdapter() { this.hasQualifiedName("io.jsonwebtoken", "JwtHandlerAdapter") }
}
/** The `on(Claims|Plaintext)Jwt` methods defined in `JwtHandler`. */
private class JwtHandlerOnJwtMethod extends Method {
JwtHandlerOnJwtMethod() {
this.hasName(["onClaimsJwt", "onPlaintextJwt"]) and
this.getNumberOfParameters() = 1 and
this.getDeclaringType() instanceof TypeJwtHandler
}
}
/** The `on(Claims|Plaintext)Jwt` methods defined in `JwtHandlerAdapter`. */
private class JwtHandlerAdapterOnJwtMethod extends Method {
JwtHandlerAdapterOnJwtMethod() {
this.hasName(["onClaimsJwt", "onPlaintextJwt"]) and
this.getNumberOfParameters() = 1 and
this.getDeclaringType() instanceof TypeJwtHandlerAdapter
}
}