Skip to content

Commit 0f013b8

Browse files
Refactor httponly cookie query
1 parent 55ce596 commit 0f013b8

File tree

1 file changed

+92
-80
lines changed

1 file changed

+92
-80
lines changed

csharp/ql/src/experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql

Lines changed: 92 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -17,91 +17,103 @@ import csharp
1717
import semmle.code.asp.WebConfig
1818
import semmle.code.csharp.frameworks.system.Web
1919
import semmle.code.csharp.frameworks.microsoft.AspNetCore
20-
deprecated import experimental.dataflow.flowsources.AuthCookie
20+
import experimental.dataflow.flowsources.AuthCookie
2121

22-
deprecated query predicate problems(Expr httpOnlySink, string message) {
22+
predicate cookieAppendHttpOnlyByDefault() {
23+
// default is set to `Always`
24+
getAValueForCookiePolicyProp("HttpOnly").getValue() = "1"
25+
or
26+
// there is an `OnAppendCookie` callback that sets `HttpOnly` to true
27+
not OnAppendCookieHttpOnlyTracking::flowTo(_)
28+
}
29+
30+
predicate httpOnlyFalse(ObjectCreation oc) {
31+
exists(Assignment a |
32+
getAValueForProp(oc, a, "HttpOnly") = a.getRValue() and
33+
a.getRValue().getValue() = "false"
34+
)
35+
}
36+
37+
predicate httpOnlyFalseOrNotSet(ObjectCreation oc) {
38+
httpOnlyFalse(oc)
39+
or
40+
not isPropertySet(oc, "HttpOnly")
41+
}
42+
43+
predicate nonHttpOnlyCookieOptionsCreation(ObjectCreation oc, MethodCall append) {
44+
// `HttpOnly` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set
45+
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
46+
httpOnlyFalseOrNotSet(oc) and
47+
exists(DataFlow::Node creation, DataFlow::Node sink |
48+
CookieOptionsTracking::flow(creation, sink) and
49+
creation.asExpr() = oc and
50+
sink.asExpr() = append.getArgument(2)
51+
)
52+
}
53+
54+
predicate nonHttpOnlySensitiveCookieCreation(ObjectCreation oc) {
55+
oc.getType() instanceof SystemWebHttpCookie and
56+
isCookieWithSensitiveName(oc.getArgument(0)) and
2357
(
24-
exists(Assignment a, Expr val |
25-
httpOnlySink = a.getRValue() and
26-
val.getValue() = "false" and
27-
(
28-
exists(ObjectCreation oc |
29-
getAValueForProp(oc, a, "HttpOnly") = val and
30-
(
31-
oc.getType() instanceof SystemWebHttpCookie and
32-
isCookieWithSensitiveName(oc.getArgument(0))
33-
or
34-
exists(MethodCall mc, MicrosoftAspNetCoreHttpResponseCookies iResponse |
35-
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
36-
iResponse.getAppendMethod() = mc.getTarget() and
37-
isCookieWithSensitiveName(mc.getArgument(0)) and
38-
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
39-
not OnAppendCookieHttpOnlyTracking::flowTo(_) and
40-
// Passed as third argument to `IResponseCookies.Append`
41-
exists(DataFlow::Node creation, DataFlow::Node append |
42-
CookieOptionsTracking::flow(creation, append) and
43-
creation.asExpr() = oc and
44-
append.asExpr() = mc.getArgument(2)
45-
)
46-
)
47-
)
48-
)
49-
or
50-
exists(PropertyWrite pw |
51-
(
52-
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieBuilder or
53-
pw.getProperty().getDeclaringType() instanceof
54-
MicrosoftAspNetCoreAuthenticationCookiesCookieAuthenticationOptions
55-
) and
56-
pw.getProperty().getName() = "HttpOnly" and
57-
a.getLValue() = pw and
58-
DataFlow::localExprFlow(val, a.getRValue())
59-
)
60-
)
61-
)
58+
httpOnlyFalse(oc)
6259
or
63-
exists(Call c |
64-
httpOnlySink = c and
60+
// the property wasn't explicitly set, so a default value from config is used
61+
not isPropertySet(oc, "HttpOnly") and
62+
// the default in config is not set to `true`
63+
not exists(XmlElement element |
64+
element instanceof HttpCookiesElement and
65+
element.(HttpCookiesElement).isHttpOnlyCookies()
66+
)
67+
)
68+
}
69+
70+
predicate sensitiveCookieAppend(MethodCall mc) {
71+
exists(MicrosoftAspNetCoreHttpResponseCookies iResponse |
72+
iResponse.getAppendMethod() = mc.getTarget() and
73+
isCookieWithSensitiveName(mc.getArgument(0))
74+
)
75+
}
76+
77+
predicate nonHttpOnlyCookieCall(Call c) {
78+
(
79+
not cookieAppendHttpOnlyByDefault() and
80+
exists(MethodCall mc |
81+
sensitiveCookieAppend(mc) and
6582
(
66-
exists(MicrosoftAspNetCoreHttpResponseCookies iResponse, MethodCall mc |
67-
// default is not configured or is not set to `Always`
68-
not getAValueForCookiePolicyProp("HttpOnly").getValue() = "1" and
69-
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
70-
not OnAppendCookieHttpOnlyTracking::flowTo(_) and
71-
iResponse.getAppendMethod() = mc.getTarget() and
72-
isCookieWithSensitiveName(mc.getArgument(0)) and
73-
(
74-
// `HttpOnly` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set
75-
exists(ObjectCreation oc |
76-
oc = c and
77-
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
78-
not isPropertySet(oc, "HttpOnly") and
79-
exists(DataFlow::Node creation |
80-
CookieOptionsTracking::flow(creation, _) and
81-
creation.asExpr() = oc
82-
)
83-
)
84-
or
85-
// IResponseCookies.Append(String, String) was called, `HttpOnly` is set to `false` by default
86-
mc = c and
87-
mc.getNumberOfArguments() < 3
88-
)
89-
)
83+
nonHttpOnlyCookieOptionsCreation(c, mc)
9084
or
91-
exists(ObjectCreation oc |
92-
oc = c and
93-
oc.getType() instanceof SystemWebHttpCookie and
94-
isCookieWithSensitiveName(oc.getArgument(0)) and
95-
// the property wasn't explicitly set, so a default value from config is used
96-
not isPropertySet(oc, "HttpOnly") and
97-
// the default in config is not set to `true`
98-
not exists(XmlElement element |
99-
element instanceof HttpCookiesElement and
100-
element.(HttpCookiesElement).isHttpOnlyCookies()
101-
)
102-
)
85+
// IResponseCookies.Append(String, String) was called, `HttpOnly` is set to `false` by default
86+
mc = c and
87+
mc.getNumberOfArguments() < 3
10388
)
10489
)
105-
) and
106-
message = "Cookie attribute 'HttpOnly' is not set to true."
90+
or
91+
nonHttpOnlySensitiveCookieCreation(c)
92+
)
10793
}
94+
95+
predicate nonHttpOnlyPolicyAssignment(Assignment a, Expr val) {
96+
val.getValue() = "false" and
97+
exists(PropertyWrite pw |
98+
(
99+
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieBuilder or
100+
pw.getProperty().getDeclaringType() instanceof
101+
MicrosoftAspNetCoreAuthenticationCookiesCookieAuthenticationOptions
102+
) and
103+
pw.getProperty().getName() = "HttpOnly" and
104+
a.getLValue() = pw and
105+
DataFlow::localExprFlow(val, a.getRValue())
106+
)
107+
}
108+
109+
from Expr httpOnlySink
110+
where
111+
(
112+
nonHttpOnlyCookieCall(httpOnlySink)
113+
or
114+
exists(Assignment a |
115+
httpOnlySink = a.getRValue() and
116+
nonHttpOnlyPolicyAssignment(a, _)
117+
)
118+
)
119+
select httpOnlySink, "Cookie attribute 'HttpOnly' is not set to true."

0 commit comments

Comments
 (0)