@@ -11,6 +11,7 @@ import java
11
11
import semmle.code.java.dataflow.FlowSteps
12
12
import semmle.code.java.frameworks.Servlets
13
13
import semmle.code.java.dataflow.TaintTracking
14
+ import semmle.code.java.dataflow.TaintTracking2
14
15
import DataFlow:: PathGraph
15
16
16
17
/** Gets a regular expression for matching common names of sensitive cookies. */
@@ -31,28 +32,6 @@ predicate isSensitiveCookieNameExpr(Expr expr) {
31
32
isSensitiveCookieNameExpr ( expr .( AddExpr ) .getAnOperand ( ) )
32
33
}
33
34
34
- /** Holds if a string is concatenated with the `HttpOnly` flag. */
35
- predicate hasHttpOnlyExpr ( Expr expr ) {
36
- (
37
- expr .( CompileTimeConstantExpr ) .getStringValue ( ) .toLowerCase ( ) .matches ( "%httponly%" )
38
- or
39
- exists (
40
- StaticMethodAccess ma // String.format("%s=%s;HttpOnly", "sessionkey", sessionKey)
41
- |
42
- ma .getType ( ) .getName ( ) = "String" and
43
- ma .getMethod ( ) .getName ( ) = "format" and
44
- ma .getArgument ( 0 )
45
- .( CompileTimeConstantExpr )
46
- .getStringValue ( )
47
- .toLowerCase ( )
48
- .matches ( "%httponly%" ) and
49
- expr = ma
50
- )
51
- )
52
- or
53
- hasHttpOnlyExpr ( expr .( AddExpr ) .getAnOperand ( ) )
54
- }
55
-
56
35
/** The method call `Set-Cookie` of `addHeader` or `setHeader`. */
57
36
class SetCookieMethodAccess extends MethodAccess {
58
37
SetCookieMethodAccess ( ) {
@@ -64,6 +43,22 @@ class SetCookieMethodAccess extends MethodAccess {
64
43
}
65
44
}
66
45
46
+ /**
47
+ * A taint configuration tracking flow from the text `httponly` to argument 1 of
48
+ * `SetCookieMethodAccess`.
49
+ */
50
+ class MatchesHttpOnlyConfiguration extends TaintTracking2:: Configuration {
51
+ MatchesHttpOnlyConfiguration ( ) { this = "MatchesHttpOnlyConfiguration" }
52
+
53
+ override predicate isSource ( DataFlow:: Node source ) {
54
+ source .asExpr ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) .toLowerCase ( ) .matches ( "%httponly%" )
55
+ }
56
+
57
+ override predicate isSink ( DataFlow:: Node sink ) {
58
+ sink .asExpr ( ) = any ( SetCookieMethodAccess ma ) .getArgument ( 1 )
59
+ }
60
+ }
61
+
67
62
/** The cookie class of Java EE. */
68
63
class CookieClass extends RefType {
69
64
CookieClass ( ) {
@@ -79,7 +74,7 @@ predicate isBooleanTrue(Expr expr) {
79
74
true
80
75
}
81
76
82
- /** Holds if the method or a wrapper method sets the `HttpOnly` flag. */
77
+ /** Holds if the method call sets the `HttpOnly` flag. */
83
78
predicate setHttpOnlyInCookie ( MethodAccess ma ) {
84
79
ma .getMethod ( ) .getName ( ) = "setHttpOnly" and
85
80
(
@@ -93,14 +88,24 @@ predicate setHttpOnlyInCookie(MethodAccess ma) {
93
88
isBooleanTrue ( mpa .getArgument ( i ) )
94
89
)
95
90
)
96
- or
97
- exists ( MethodAccess mca |
98
- ma .getMethod ( ) .calls ( mca .getMethod ( ) ) and
99
- setHttpOnlyInCookie ( mca )
100
- )
101
91
}
102
92
103
- /** Holds if the method or a wrapper method removes a cookie. */
93
+ /**
94
+ * A taint configuration tracking flow of a method or a wrapper method that sets
95
+ * the `HttpOnly` flag.
96
+ */
97
+ class SetHttpOnlyInCookieConfiguration extends TaintTracking2:: Configuration {
98
+ SetHttpOnlyInCookieConfiguration ( ) { this = "SetHttpOnlyInCookieConfiguration" }
99
+
100
+ override predicate isSource ( DataFlow:: Node source ) { any ( ) }
101
+
102
+ override predicate isSink ( DataFlow:: Node sink ) {
103
+ sink .asExpr ( ) =
104
+ any ( MethodAccess ma | ma .getMethod ( ) instanceof ResponseAddCookieMethod ) .getArgument ( 0 )
105
+ }
106
+ }
107
+
108
+ /** Holds if the method call removes a cookie. */
104
109
predicate removeCookie ( MethodAccess ma ) {
105
110
ma .getMethod ( ) .getName ( ) = "setMaxAge" and
106
111
ma .getArgument ( 0 ) .( IntegerLiteral ) .getIntValue ( ) = 0
@@ -125,15 +130,14 @@ class CookieResponseSink extends DataFlow::ExprNode {
125
130
setHttpOnlyInCookie ( ma2 ) or
126
131
removeCookie ( ma2 )
127
132
) and
128
- (
129
- DataFlow:: localExprFlow ( ma2 .getQualifier ( ) , this .getExpr ( ) ) or
130
- DataFlow:: localExprFlow ( ma2 , this .getExpr ( ) )
133
+ exists ( SetHttpOnlyInCookieConfiguration cc |
134
+ cc .hasFlow ( DataFlow:: exprNode ( ma2 .getQualifier ( ) ) , this )
131
135
)
132
136
)
133
137
or
134
138
ma instanceof SetCookieMethodAccess and
135
139
this .getExpr ( ) = ma .getArgument ( 1 ) and
136
- not hasHttpOnlyExpr ( this . getExpr ( ) ) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure")
140
+ not exists ( MatchesHttpOnlyConfiguration cc | cc . hasFlowToExpr ( ma . getArgument ( 1 ) ) ) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure")
137
141
) and
138
142
not isTestMethod ( ma ) // Test class or method
139
143
)
0 commit comments