Skip to content

Commit 5164c24

Browse files
committed
Refactor SensitiveCookieNotHttpOnly
1 parent 8f7d8cb commit 5164c24

File tree

1 file changed

+23
-24
lines changed

1 file changed

+23
-24
lines changed

java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import semmle.code.java.dataflow.FlowSteps
2525
import semmle.code.java.frameworks.Servlets
2626
import semmle.code.java.dataflow.TaintTracking
2727
import semmle.code.java.dataflow.TaintTracking2
28-
import DataFlow::PathGraph
28+
import MissingHttpOnlyFlow::PathGraph
2929

3030
/** Gets a regular expression for matching common names of sensitive cookies. */
3131
string getSensitiveCookieNameRegex() { result = "(?i).*(auth|session|token|key|credential).*" }
@@ -65,18 +65,18 @@ class SetCookieMethodAccess extends MethodAccess {
6565
* A taint configuration tracking flow from the text `httponly` to argument 1 of
6666
* `SetCookieMethodAccess`.
6767
*/
68-
class MatchesHttpOnlyConfiguration extends TaintTracking2::Configuration {
69-
MatchesHttpOnlyConfiguration() { this = "MatchesHttpOnlyConfiguration" }
70-
71-
override predicate isSource(DataFlow::Node source) {
68+
module MatchesHttpOnlyConfig implements DataFlow::ConfigSig {
69+
predicate isSource(DataFlow::Node source) {
7270
source.asExpr().(CompileTimeConstantExpr).getStringValue().toLowerCase().matches("%httponly%")
7371
}
7472

75-
override predicate isSink(DataFlow::Node sink) {
73+
predicate isSink(DataFlow::Node sink) {
7674
sink.asExpr() = any(SetCookieMethodAccess ma).getArgument(1)
7775
}
7876
}
7977

78+
module MatchesHttpOnlyFlow = TaintTracking::Global<MatchesHttpOnlyConfig>;
79+
8080
/** A class descended from `javax.servlet.http.Cookie`. */
8181
class CookieClass extends RefType {
8282
CookieClass() { this.getAnAncestor().hasQualifiedName("javax.servlet.http", "Cookie") }
@@ -126,20 +126,21 @@ predicate isTestMethod(MethodAccess ma) {
126126
* A taint configuration tracking flow of a method that sets the `HttpOnly` flag,
127127
* or one that removes a cookie, to a `ServletResponse.addCookie` call.
128128
*/
129-
class SetHttpOnlyOrRemovesCookieConfiguration extends TaintTracking2::Configuration {
130-
SetHttpOnlyOrRemovesCookieConfiguration() { this = "SetHttpOnlyOrRemovesCookieConfiguration" }
131-
132-
override predicate isSource(DataFlow::Node source) {
129+
module SetHttpOnlyOrRemovesCookieConfiguration implements DataFlow::ConfigSig {
130+
predicate isSource(DataFlow::Node source) {
133131
source.asExpr() =
134132
any(MethodAccess ma | setsCookieHttpOnly(ma) or removesCookie(ma)).getQualifier()
135133
}
136134

137-
override predicate isSink(DataFlow::Node sink) {
135+
predicate isSink(DataFlow::Node sink) {
138136
sink.asExpr() =
139137
any(MethodAccess ma | ma.getMethod() instanceof ResponseAddCookieMethod).getArgument(0)
140138
}
141139
}
142140

141+
module SetHttpOnlyOrRemovesCookieFlow =
142+
TaintTracking::Global<SetHttpOnlyOrRemovesCookieConfiguration>;
143+
143144
/**
144145
* A cookie that is added to an HTTP response and which doesn't have `httpOnly` set, used as a sink
145146
* in `MissingHttpOnlyConfiguration`.
@@ -150,11 +151,11 @@ class CookieResponseSink extends DataFlow::ExprNode {
150151
(
151152
ma.getMethod() instanceof ResponseAddCookieMethod and
152153
this.getExpr() = ma.getArgument(0) and
153-
not exists(SetHttpOnlyOrRemovesCookieConfiguration cc | cc.hasFlowTo(this))
154+
not SetHttpOnlyOrRemovesCookieFlow::flowTo(this)
154155
or
155156
ma instanceof SetCookieMethodAccess and
156157
this.getExpr() = ma.getArgument(1) and
157-
not exists(MatchesHttpOnlyConfiguration cc | cc.hasFlowTo(this)) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure")
158+
not MatchesHttpOnlyFlow::flowTo(this) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure")
158159
) and
159160
not isTestMethod(ma) // Test class or method
160161
)
@@ -181,21 +182,17 @@ predicate setsHttpOnlyInNewCookie(ClassInstanceExpr cie) {
181182
* A taint configuration tracking flow from a sensitive cookie without the `HttpOnly` flag
182183
* set to its HTTP response.
183184
*/
184-
class MissingHttpOnlyConfiguration extends TaintTracking::Configuration {
185-
MissingHttpOnlyConfiguration() { this = "MissingHttpOnlyConfiguration" }
185+
module MissingHttpOnlyConfig implements DataFlow::ConfigSig {
186+
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveCookieNameExpr }
186187

187-
override predicate isSource(DataFlow::Node source) {
188-
source.asExpr() instanceof SensitiveCookieNameExpr
189-
}
190-
191-
override predicate isSink(DataFlow::Node sink) { sink instanceof CookieResponseSink }
188+
predicate isSink(DataFlow::Node sink) { sink instanceof CookieResponseSink }
192189

193-
override predicate isSanitizer(DataFlow::Node node) {
190+
predicate isBarrier(DataFlow::Node node) {
194191
// JAX-RS's `new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true)` and similar
195192
setsHttpOnlyInNewCookie(node.asExpr())
196193
}
197194

198-
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
195+
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
199196
exists(
200197
ConstructorCall cc // new Cookie(...)
201198
|
@@ -215,7 +212,9 @@ class MissingHttpOnlyConfiguration extends TaintTracking::Configuration {
215212
}
216213
}
217214

218-
from DataFlow::PathNode source, DataFlow::PathNode sink, MissingHttpOnlyConfiguration c
219-
where c.hasFlowPath(source, sink)
215+
module MissingHttpOnlyFlow = TaintTracking::Global<MissingHttpOnlyConfig>;
216+
217+
from MissingHttpOnlyFlow::PathNode source, MissingHttpOnlyFlow::PathNode sink
218+
where MissingHttpOnlyFlow::flowPath(source, sink)
220219
select sink.getNode(), source, sink, "$@ doesn't have the HttpOnly flag set.", source.getNode(),
221220
"This sensitive cookie"

0 commit comments

Comments
 (0)