Skip to content

Commit 85dc109

Browse files
authored
Merge pull request #9116 from smowton/smowton/feature/accept-conditional-cookie-security
Java: tolerate `cookie.setSecure(request.isSecure())`
2 parents 46ab25b + 0044326 commit 85dc109

File tree

5 files changed

+106
-22
lines changed

5 files changed

+106
-22
lines changed

java/ql/lib/semmle/code/java/frameworks/Servlets.qll

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import semmle.code.java.Type
88
* The interface `javax.servlet.ServletRequest` or
99
* `javax.servlet.http.HttpServletRequest`.
1010
*/
11-
library class ServletRequest extends RefType {
11+
class ServletRequest extends RefType {
1212
ServletRequest() {
1313
this.hasQualifiedName("javax.servlet", "ServletRequest") or
1414
this instanceof HttpServletRequest
@@ -18,15 +18,15 @@ library class ServletRequest extends RefType {
1818
/**
1919
* The interface `javax.servlet.http.HttpServletRequest`.
2020
*/
21-
library class HttpServletRequest extends RefType {
21+
class HttpServletRequest extends RefType {
2222
HttpServletRequest() { this.hasQualifiedName("javax.servlet.http", "HttpServletRequest") }
2323
}
2424

2525
/**
2626
* The method `getParameter(String)` or `getParameterValues(String)`
2727
* declared in `javax.servlet.ServletRequest`.
2828
*/
29-
library class ServletRequestGetParameterMethod extends Method {
29+
class ServletRequestGetParameterMethod extends Method {
3030
ServletRequestGetParameterMethod() {
3131
this.getDeclaringType() instanceof ServletRequest and
3232
(
@@ -41,7 +41,7 @@ library class ServletRequestGetParameterMethod extends Method {
4141
/**
4242
* The method `getParameterNames()` declared in `javax.servlet.ServletRequest`.
4343
*/
44-
library class ServletRequestGetParameterNamesMethod extends Method {
44+
class ServletRequestGetParameterNamesMethod extends Method {
4545
ServletRequestGetParameterNamesMethod() {
4646
this.getDeclaringType() instanceof ServletRequest and
4747
this.hasName("getParameterNames") and
@@ -52,7 +52,7 @@ library class ServletRequestGetParameterNamesMethod extends Method {
5252
/**
5353
* The method `getParameterMap()` declared in `javax.servlet.ServletRequest`.
5454
*/
55-
library class ServletRequestGetParameterMapMethod extends Method {
55+
class ServletRequestGetParameterMapMethod extends Method {
5656
ServletRequestGetParameterMapMethod() {
5757
this.getDeclaringType() instanceof ServletRequest and
5858
this.hasName("getParameterMap") and
@@ -63,7 +63,7 @@ library class ServletRequestGetParameterMapMethod extends Method {
6363
/**
6464
* The method `getQueryString()` declared in `javax.servlet.http.HttpServletRequest`.
6565
*/
66-
library class HttpServletRequestGetQueryStringMethod extends Method {
66+
class HttpServletRequestGetQueryStringMethod extends Method {
6767
HttpServletRequestGetQueryStringMethod() {
6868
this.getDeclaringType() instanceof HttpServletRequest and
6969
this.hasName("getQueryString") and
@@ -85,7 +85,7 @@ class HttpServletRequestGetPathMethod extends Method {
8585
/**
8686
* The method `getHeader(String)` declared in `javax.servlet.http.HttpServletRequest`.
8787
*/
88-
library class HttpServletRequestGetHeaderMethod extends Method {
88+
class HttpServletRequestGetHeaderMethod extends Method {
8989
HttpServletRequestGetHeaderMethod() {
9090
this.getDeclaringType() instanceof HttpServletRequest and
9191
this.hasName("getHeader") and
@@ -97,7 +97,7 @@ library class HttpServletRequestGetHeaderMethod extends Method {
9797
/**
9898
* The method `getHeaders(String)` declared in `javax.servlet.http.HttpServletRequest`.
9999
*/
100-
library class HttpServletRequestGetHeadersMethod extends Method {
100+
class HttpServletRequestGetHeadersMethod extends Method {
101101
HttpServletRequestGetHeadersMethod() {
102102
this.getDeclaringType() instanceof HttpServletRequest and
103103
this.hasName("getHeaders") and
@@ -109,7 +109,7 @@ library class HttpServletRequestGetHeadersMethod extends Method {
109109
/**
110110
* The method `getHeaderNames()` declared in `javax.servlet.http.HttpServletRequest`.
111111
*/
112-
library class HttpServletRequestGetHeaderNamesMethod extends Method {
112+
class HttpServletRequestGetHeaderNamesMethod extends Method {
113113
HttpServletRequestGetHeaderNamesMethod() {
114114
this.getDeclaringType() instanceof HttpServletRequest and
115115
this.hasName("getHeaderNames") and
@@ -145,7 +145,7 @@ class HttpServletRequestGetRequestURIMethod extends Method {
145145
/**
146146
* The method `getRemoteUser()` declared in `javax.servlet.http.HttpServletRequest`.
147147
*/
148-
library class HttpServletRequestGetRemoteUserMethod extends Method {
148+
class HttpServletRequestGetRemoteUserMethod extends Method {
149149
HttpServletRequestGetRemoteUserMethod() {
150150
this.getDeclaringType() instanceof HttpServletRequest and
151151
this.hasName("getRemoteUser") and
@@ -156,7 +156,7 @@ library class HttpServletRequestGetRemoteUserMethod extends Method {
156156
/**
157157
* The method `getInputStream()` or `getReader()` declared in `javax.servlet.ServletRequest`.
158158
*/
159-
library class ServletRequestGetBodyMethod extends Method {
159+
class ServletRequestGetBodyMethod extends Method {
160160
ServletRequestGetBodyMethod() {
161161
this.getDeclaringType() instanceof ServletRequest and
162162
(this.hasName("getInputStream") or this.hasName("getReader"))
@@ -239,14 +239,14 @@ class ServletResponseGetOutputStreamMethod extends Method {
239239
}
240240

241241
/** The class `javax.servlet.http.Cookie`. */
242-
library class TypeCookie extends Class {
242+
class TypeCookie extends Class {
243243
TypeCookie() { this.hasQualifiedName("javax.servlet.http", "Cookie") }
244244
}
245245

246246
/**
247247
* The method `getValue(String)` declared in `javax.servlet.http.Cookie`.
248248
*/
249-
library class CookieGetValueMethod extends Method {
249+
class CookieGetValueMethod extends Method {
250250
CookieGetValueMethod() {
251251
this.getDeclaringType() instanceof TypeCookie and
252252
this.hasName("getValue") and
@@ -257,7 +257,7 @@ library class CookieGetValueMethod extends Method {
257257
/**
258258
* The method `getName()` declared in `javax.servlet.http.Cookie`.
259259
*/
260-
library class CookieGetNameMethod extends Method {
260+
class CookieGetNameMethod extends Method {
261261
CookieGetNameMethod() {
262262
this.getDeclaringType() instanceof TypeCookie and
263263
this.hasName("getName") and
@@ -269,7 +269,7 @@ library class CookieGetNameMethod extends Method {
269269
/**
270270
* The method `getComment()` declared in `javax.servlet.http.Cookie`.
271271
*/
272-
library class CookieGetCommentMethod extends Method {
272+
class CookieGetCommentMethod extends Method {
273273
CookieGetCommentMethod() {
274274
this.getDeclaringType() instanceof TypeCookie and
275275
this.hasName("getComment") and

java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,31 @@
1313

1414
import java
1515
import semmle.code.java.frameworks.Servlets
16+
import semmle.code.java.dataflow.DataFlow
17+
18+
predicate isSafeSecureCookieSetting(Expr e) {
19+
e.(CompileTimeConstantExpr).getBooleanValue() = true
20+
or
21+
exists(Method isSecure |
22+
isSecure.getName() = "isSecure" and
23+
isSecure.getDeclaringType().getASourceSupertype*() instanceof ServletRequest
24+
|
25+
e.(MethodAccess).getMethod() = isSecure
26+
)
27+
}
1628

1729
from MethodAccess add
1830
where
1931
add.getMethod() instanceof ResponseAddCookieMethod and
2032
not exists(Variable cookie, MethodAccess m |
2133
add.getArgument(0) = cookie.getAnAccess() and
2234
m.getMethod().getName() = "setSecure" and
23-
m.getArgument(0).(CompileTimeConstantExpr).getBooleanValue() = true and
35+
forex(DataFlow::Node argSource |
36+
DataFlow::localFlow(argSource, DataFlow::exprNode(m.getArgument(0))) and
37+
not DataFlow::localFlowStep(_, argSource)
38+
|
39+
isSafeSecureCookieSetting(argSource.asExpr())
40+
) and
2441
m.getQualifier() = cookie.getAnAccess()
2542
)
2643
select add, "Cookie is added to response without the 'secure' flag being set."
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Query `java/insecure-cookie` now tolerates setting a cookie's secure flag to `request.isSecure()`. This means servlets that intentionally accept unencrypted connections will no longer raise an alert.
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
| Test.java:16:4:16:29 | addCookie(...) | Cookie is added to response without the 'secure' flag being set. |
1+
| Test.java:19:4:19:29 | addCookie(...) | Cookie is added to response without the 'secure' flag being set. |
2+
| Test.java:28:4:28:29 | addCookie(...) | Cookie is added to response without the 'secure' flag being set. |
3+
| Test.java:37:4:37:29 | addCookie(...) | Cookie is added to response without the 'secure' flag being set. |
4+
| Test.java:51:4:51:29 | addCookie(...) | Cookie is added to response without the 'secure' flag being set. |

java/ql/test/query-tests/security/CWE-311/CWE-614/semmle/tests/Test.java

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,81 @@
88
import javax.servlet.http.*;
99

1010
class Test {
11-
public static void test(HttpServletRequest request, HttpServletResponse response) {
11+
12+
public static final boolean constTrue = true;
13+
14+
public static void test(HttpServletRequest request, HttpServletResponse response, boolean alwaysSecure, boolean otherInput) {
1215
{
1316
Cookie cookie = new Cookie("secret" ,"fakesecret");
14-
17+
1518
// BAD: secure flag not set
1619
response.addCookie(cookie);
17-
20+
1821
}
19-
22+
2023
{
2124
Cookie cookie = new Cookie("secret" ,"fakesecret");
22-
25+
26+
// BAD: secure flag set to false
27+
cookie.setSecure(false);
28+
response.addCookie(cookie);
29+
30+
}
31+
32+
{
33+
Cookie cookie = new Cookie("secret" ,"fakesecret");
34+
35+
// BAD: secure flag set to something not clearly true or request.isSecure()
36+
cookie.setSecure(otherInput);
37+
response.addCookie(cookie);
38+
39+
}
40+
41+
{
42+
Cookie cookie = new Cookie("secret" ,"fakesecret");
43+
44+
// BAD: secure flag sometimes set to something clearly true or request.isSecure()
45+
boolean secureVal;
46+
if(alwaysSecure)
47+
secureVal = true;
48+
else
49+
secureVal = otherInput;
50+
cookie.setSecure(secureVal);
51+
response.addCookie(cookie);
52+
53+
}
54+
55+
{
56+
Cookie cookie = new Cookie("secret" ,"fakesecret");
57+
58+
// GOOD: set secure flag
59+
cookie.setSecure(true);
60+
response.addCookie(cookie);
61+
}
62+
63+
{
64+
Cookie cookie = new Cookie("secret" ,"fakesecret");
65+
2366
// GOOD: set secure flag
2467
cookie.setSecure(true);
2568
response.addCookie(cookie);
2669
}
70+
71+
{
72+
Cookie cookie = new Cookie("secret" ,"fakesecret");
73+
74+
// GOOD: set secure flag
75+
cookie.setSecure(constTrue);
76+
response.addCookie(cookie);
77+
}
78+
79+
{
80+
Cookie cookie = new Cookie("secret" ,"fakesecret");
81+
82+
// GOOD: set secure flag if contacted over HTTPS
83+
cookie.setSecure(alwaysSecure ? true : request.isSecure());
84+
response.addCookie(cookie);
85+
}
86+
2787
}
2888
}

0 commit comments

Comments
 (0)