@@ -11,6 +11,7 @@ import java
1111import semmle.code.java.dataflow.FlowSteps
1212import semmle.code.java.frameworks.Servlets
1313import semmle.code.java.dataflow.TaintTracking
14+ import semmle.code.java.dataflow.TaintTracking2
1415import DataFlow:: PathGraph
1516
1617/** Gets a regular expression for matching common names of sensitive cookies. */
@@ -31,28 +32,6 @@ predicate isSensitiveCookieNameExpr(Expr expr) {
3132 isSensitiveCookieNameExpr ( expr .( AddExpr ) .getAnOperand ( ) )
3233}
3334
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-
5635/** The method call `Set-Cookie` of `addHeader` or `setHeader`. */
5736class SetCookieMethodAccess extends MethodAccess {
5837 SetCookieMethodAccess ( ) {
@@ -64,6 +43,22 @@ class SetCookieMethodAccess extends MethodAccess {
6443 }
6544}
6645
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+
6762/** The cookie class of Java EE. */
6863class CookieClass extends RefType {
6964 CookieClass ( ) {
@@ -79,7 +74,7 @@ predicate isBooleanTrue(Expr expr) {
7974 true
8075}
8176
82- /** Holds if the method or a wrapper method sets the `HttpOnly` flag. */
77+ /** Holds if the method call sets the `HttpOnly` flag. */
8378predicate setHttpOnlyInCookie ( MethodAccess ma ) {
8479 ma .getMethod ( ) .getName ( ) = "setHttpOnly" and
8580 (
@@ -93,14 +88,24 @@ predicate setHttpOnlyInCookie(MethodAccess ma) {
9388 isBooleanTrue ( mpa .getArgument ( i ) )
9489 )
9590 )
96- or
97- exists ( MethodAccess mca |
98- ma .getMethod ( ) .calls ( mca .getMethod ( ) ) and
99- setHttpOnlyInCookie ( mca )
100- )
10191}
10292
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. */
104109predicate removeCookie ( MethodAccess ma ) {
105110 ma .getMethod ( ) .getName ( ) = "setMaxAge" and
106111 ma .getArgument ( 0 ) .( IntegerLiteral ) .getIntValue ( ) = 0
@@ -125,15 +130,14 @@ class CookieResponseSink extends DataFlow::ExprNode {
125130 setHttpOnlyInCookie ( ma2 ) or
126131 removeCookie ( ma2 )
127132 ) 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 )
131135 )
132136 )
133137 or
134138 ma instanceof SetCookieMethodAccess and
135139 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")
137141 ) and
138142 not isTestMethod ( ma ) // Test class or method
139143 )
0 commit comments