Remove experimental query and tests

This commit is contained in:
Joe Farebrother
2025-10-02 09:59:44 +01:00
parent c799f93811
commit c4781146c0
7 changed files with 0 additions and 529 deletions

View File

@@ -1,44 +0,0 @@
class SensitiveCookieNotHttpOnly {
// GOOD - Create a sensitive cookie with the `HttpOnly` flag set.
public void addCookie(String jwt_token, HttpServletRequest request, HttpServletResponse response) {
Cookie jwtCookie =new Cookie("jwt_token", jwt_token);
jwtCookie.setPath("/");
jwtCookie.setMaxAge(3600*24*7);
jwtCookie.setHttpOnly(true);
response.addCookie(jwtCookie);
}
// BAD - Create a sensitive cookie without the `HttpOnly` flag set.
public void addCookie2(String jwt_token, String userId, HttpServletRequest request, HttpServletResponse response) {
Cookie jwtCookie =new Cookie("jwt_token", jwt_token);
jwtCookie.setPath("/");
jwtCookie.setMaxAge(3600*24*7);
response.addCookie(jwtCookie);
}
// GOOD - Set a sensitive cookie header with the `HttpOnly` flag set.
public void addCookie3(String authId, HttpServletRequest request, HttpServletResponse response) {
response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure");
}
// BAD - Set a sensitive cookie header without the `HttpOnly` flag set.
public void addCookie4(String authId, HttpServletRequest request, HttpServletResponse response) {
response.addHeader("Set-Cookie", "token=" +authId + ";Secure");
}
// GOOD - Set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` with the `HttpOnly` flag set through string concatenation.
public void addCookie5(String accessKey, HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Set-Cookie", new NewCookie("session-access-key", accessKey, "/", null, null, 0, true) + ";HttpOnly");
}
// BAD - Set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` without the `HttpOnly` flag set.
public void addCookie6(String accessKey, HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Set-Cookie", new NewCookie("session-access-key", accessKey, "/", null, null, 0, true).toString());
}
// GOOD - Set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` with the `HttpOnly` flag set through the constructor.
public void addCookie7(String accessKey, HttpServletRequest request, HttpServletResponse response) {
NewCookie accessKeyCookie = new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true);
response.setHeader("Set-Cookie", accessKeyCookie.toString());
}
}

View File

@@ -1,27 +0,0 @@
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
<qhelp>
<overview>
<p>Cross-Site Scripting (XSS) is categorized as one of the OWASP Top 10 Security Vulnerabilities. The <code>HttpOnly</code> flag directs compatible browsers to prevent client-side script from accessing cookies. Including the <code>HttpOnly</code> flag in the Set-Cookie HTTP response header for a sensitive cookie helps mitigate the risk associated with XSS where an attacker's script code attempts to read the contents of a cookie and exfiltrate information obtained.</p>
</overview>
<recommendation>
<p>Use the <code>HttpOnly</code> flag when generating a cookie containing sensitive information to help mitigate the risk of client side script accessing the protected cookie.</p>
</recommendation>
<example>
<p>The following example shows two ways of generating sensitive cookies. In the 'BAD' cases, the <code>HttpOnly</code> flag is not set. In the 'GOOD' cases, the <code>HttpOnly</code> flag is set.</p>
<sample src="SensitiveCookieNotHttpOnly.java" />
</example>
<references>
<li>
PortSwigger:
<a href="https://portswigger.net/kb/issues/00500600_cookie-without-httponly-flag-set">Cookie without HttpOnly flag set</a>
</li>
<li>
OWASP:
<a href="https://owasp.org/www-community/HttpOnly">HttpOnly</a>
</li>
</references>
</qhelp>

View File

@@ -1,224 +0,0 @@
/**
* @name Sensitive cookies without the HttpOnly response header set
* @description Sensitive cookies without the 'HttpOnly' flag set leaves session cookies vulnerable to
* an XSS attack.
* @kind path-problem
* @problem.severity warning
* @precision medium
* @id java/sensitive-cookie-not-httponly
* @tags security
* experimental
* external/cwe/cwe-1004
*/
/*
* Sketch of the structure of this query: we track cookie names that appear to be sensitive
* (e.g. `session` or `token`) to a `ServletResponse.addHeader(...)` or `.addCookie(...)`
* method that does not set the `httpOnly` flag. Subsidiary configurations
* `MatchesHttpOnlyConfiguration` and `SetHttpOnlyInCookieConfiguration` are used to establish
* when the `httpOnly` flag is likely to have been set, before configuration
* `MissingHttpOnlyConfiguration` establishes that a non-`httpOnly` cookie has a sensitive-seeming name.
*/
import java
import semmle.code.java.dataflow.FlowSteps
import semmle.code.java.frameworks.Servlets
import semmle.code.java.dataflow.TaintTracking
import MissingHttpOnlyFlow::PathGraph
/** Gets a regular expression for matching common names of sensitive cookies. */
string getSensitiveCookieNameRegex() { result = "(?i).*(auth|session|token|key|credential).*" }
/** Gets a regular expression for matching CSRF cookies. */
string getCsrfCookieNameRegex() { result = "(?i).*(csrf).*" }
/**
* Holds if a string is concatenated with the name of a sensitive cookie. Excludes CSRF cookies since
* they are special cookies implementing the Synchronizer Token Pattern that can be used in JavaScript.
*/
predicate isSensitiveCookieNameExpr(Expr expr) {
exists(string s | s = expr.(CompileTimeConstantExpr).getStringValue() |
s.regexpMatch(getSensitiveCookieNameRegex()) and not s.regexpMatch(getCsrfCookieNameRegex())
)
or
isSensitiveCookieNameExpr(expr.(AddExpr).getAnOperand())
}
/** A sensitive cookie name. */
class SensitiveCookieNameExpr extends Expr {
SensitiveCookieNameExpr() { isSensitiveCookieNameExpr(this) }
}
/** A method call that sets a `Set-Cookie` header. */
class SetCookieMethodCall extends MethodCall {
SetCookieMethodCall() {
(
this.getMethod() instanceof ResponseAddHeaderMethod or
this.getMethod() instanceof ResponseSetHeaderMethod
) and
this.getArgument(0).(CompileTimeConstantExpr).getStringValue().toLowerCase() = "set-cookie"
}
}
/**
* A taint configuration tracking flow from the text `httponly` to argument 1 of
* `SetCookieMethodCall`.
*/
module MatchesHttpOnlyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(CompileTimeConstantExpr).getStringValue().toLowerCase().matches("%httponly%")
}
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(SetCookieMethodCall ma).getArgument(1)
}
}
module MatchesHttpOnlyFlow = TaintTracking::Global<MatchesHttpOnlyConfig>;
/** A class descended from `javax.servlet.http.Cookie`. */
class CookieClass extends RefType {
CookieClass() { this.getAnAncestor().hasQualifiedName("javax.servlet.http", "Cookie") }
}
/** Holds if `expr` is any boolean-typed expression other than literal `false`. */
// Inlined because this could be a very large result set if computed out of context
pragma[inline]
predicate mayBeBooleanTrue(Expr expr) {
expr.getType() instanceof BooleanType and
not expr.(CompileTimeConstantExpr).getBooleanValue() = false
}
/** Holds if the method call may set the `HttpOnly` flag. */
predicate setsCookieHttpOnly(MethodCall ma) {
ma.getMethod().getName() = "setHttpOnly" and
// any use of setHttpOnly(x) where x isn't false is probably safe
mayBeBooleanTrue(ma.getArgument(0))
}
/** Holds if `ma` removes a cookie. */
predicate removesCookie(MethodCall ma) {
ma.getMethod().getName() = "setMaxAge" and
ma.getArgument(0).(IntegerLiteral).getIntValue() = 0
}
/**
* Holds if the MethodCall `ma` is a test method call indicated by:
* a) in a test directory such as `src/test/java`
* b) in a test package whose name has the word `test`
* c) in a test class whose name has the word `test`
* d) in a test class implementing a test framework such as JUnit or TestNG
*/
predicate isTestMethod(MethodCall ma) {
exists(Method m |
m = ma.getEnclosingCallable() and
(
m.getDeclaringType().getName().toLowerCase().matches("%test%") or // Simple check to exclude test classes to reduce FPs
m.getDeclaringType().getPackage().getName().toLowerCase().matches("%test%") or // Simple check to exclude classes in test packages to reduce FPs
exists(m.getLocation().getFile().getAbsolutePath().indexOf("/src/test/java")) or // Match test directory structure of build tools like maven
m instanceof TestMethod // Test method of a test case implementing a test framework such as JUnit or TestNG
)
)
}
/**
* A taint configuration tracking flow of a method that sets the `HttpOnly` flag,
* or one that removes a cookie, to a `ServletResponse.addCookie` call.
*/
module SetHttpOnlyOrRemovesCookieConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr() =
any(MethodCall ma | setsCookieHttpOnly(ma) or removesCookie(ma)).getQualifier()
}
predicate isSink(DataFlow::Node sink) {
sink.asExpr() =
any(MethodCall ma | ma.getMethod() instanceof ResponseAddCookieMethod).getArgument(0)
}
}
module SetHttpOnlyOrRemovesCookieFlow = TaintTracking::Global<SetHttpOnlyOrRemovesCookieConfig>;
/**
* A cookie that is added to an HTTP response and which doesn't have `httpOnly` set, used as a sink
* in `MissingHttpOnlyConfiguration`.
*/
class CookieResponseSink extends DataFlow::ExprNode {
CookieResponseSink() {
exists(MethodCall ma |
(
ma.getMethod() instanceof ResponseAddCookieMethod and
this.getExpr() = ma.getArgument(0) and
not SetHttpOnlyOrRemovesCookieFlow::flowTo(this)
or
ma instanceof SetCookieMethodCall and
this.getExpr() = ma.getArgument(1) and
not MatchesHttpOnlyFlow::flowTo(this) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure")
) and
not isTestMethod(ma) // Test class or method
)
}
}
/** Holds if `cie` is an invocation of a JAX-RS `NewCookie` constructor that sets `HttpOnly` to true. */
predicate setsHttpOnlyInNewCookie(ClassInstanceExpr cie) {
cie.getConstructedType().hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "NewCookie") and
(
cie.getNumArgument() = 6 and
mayBeBooleanTrue(cie.getArgument(5)) // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly)
or
cie.getNumArgument() = 8 and
cie.getArgument(6).getType() instanceof BooleanType and
mayBeBooleanTrue(cie.getArgument(7)) // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly)
or
cie.getNumArgument() = 10 and
mayBeBooleanTrue(cie.getArgument(9)) // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly)
)
}
/**
* A taint configuration tracking flow from a sensitive cookie without the `HttpOnly` flag
* set to its HTTP response.
*/
module MissingHttpOnlyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveCookieNameExpr }
predicate isSink(DataFlow::Node sink) { sink instanceof CookieResponseSink }
predicate isBarrier(DataFlow::Node node) {
// JAX-RS's `new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true)` and similar
setsHttpOnlyInNewCookie(node.asExpr())
}
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(
ConstructorCall cc // new Cookie(...)
|
cc.getConstructedType() instanceof CookieClass and
pred.asExpr() = cc.getAnArgument() and
succ.asExpr() = cc
)
or
exists(
MethodCall ma // cookie.toString()
|
ma.getMethod().getName() = "toString" and
ma.getQualifier().getType() instanceof CookieClass and
pred.asExpr() = ma.getQualifier() and
succ.asExpr() = ma
)
}
}
module MissingHttpOnlyFlow = TaintTracking::Global<MissingHttpOnlyConfig>;
deprecated query predicate problems(
DataFlow::Node sinkNode, MissingHttpOnlyFlow::PathNode source, MissingHttpOnlyFlow::PathNode sink,
string message1, DataFlow::Node sourceNode, string message2
) {
MissingHttpOnlyFlow::flowPath(source, sink) and
sinkNode = sink.getNode() and
message1 = "$@ doesn't have the HttpOnly flag set." and
sourceNode = source.getNode() and
message2 = "This sensitive cookie"
}

View File

@@ -1,67 +0,0 @@
edges
| SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | provenance | |
| SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | provenance | Sink:MaD:1 |
| SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie | provenance | Config |
| SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie | provenance | MaD:4 |
| SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | provenance | Sink:MaD:2 |
| SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | provenance | Sink:MaD:2 |
| SensitiveCookieNotHttpOnly.java:52:42:52:113 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | provenance | MaD:5 Sink:MaD:3 |
| SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:52:42:52:113 | new NewCookie(...) : NewCookie | provenance | MaD:6 |
| SensitiveCookieNotHttpOnly.java:63:37:63:115 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:64:25:64:39 | accessKeyCookie : NewCookie | provenance | |
| SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:63:37:63:115 | new NewCookie(...) : NewCookie | provenance | MaD:6 |
| SensitiveCookieNotHttpOnly.java:64:25:64:39 | accessKeyCookie : NewCookie | SensitiveCookieNotHttpOnly.java:64:25:64:50 | toString(...) : String | provenance | MaD:5 |
| SensitiveCookieNotHttpOnly.java:64:25:64:50 | toString(...) : String | SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | provenance | Sink:MaD:3 |
| SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | provenance | Sink:MaD:2 |
| SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | provenance | Sink:MaD:2 |
| SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | provenance | Sink:MaD:2 |
| SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String | provenance | |
| SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | provenance | |
| SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String | SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie | provenance | Config |
| SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String | SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie | provenance | MaD:4 |
| SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | provenance | |
| SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | provenance | Sink:MaD:1 |
models
| 1 | Sink: javax.servlet.http; HttpServletResponse; false; addCookie; ; ; Argument[0]; response-splitting; manual |
| 2 | Sink: javax.servlet.http; HttpServletResponse; false; addHeader; ; ; Argument[0..1]; response-splitting; manual |
| 3 | Sink: javax.servlet.http; HttpServletResponse; false; setHeader; ; ; Argument[0..1]; response-splitting; manual |
| 4 | Summary: javax.servlet.http; Cookie; false; Cookie; ; ; Argument[0]; Argument[this]; taint; manual |
| 5 | Summary: javax.ws.rs.core; Cookie; true; toString; ; ; Argument[this]; ReturnValue; taint; manual |
| 6 | Summary: javax.ws.rs.core; NewCookie; false; NewCookie; ; ; Argument[0..9]; Argument[this]; taint; manual |
nodes
| SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | semmle.label | "jwt_token" : String |
| SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie | semmle.label | new Cookie(...) : Cookie |
| SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | semmle.label | tokenCookieStr : String |
| SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | semmle.label | jwtCookie |
| SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | semmle.label | "token=" : String |
| SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | semmle.label | ... + ... : String |
| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | semmle.label | ... + ... |
| SensitiveCookieNotHttpOnly.java:52:42:52:113 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie |
| SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | semmle.label | toString(...) |
| SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | semmle.label | "session-access-key" : String |
| SensitiveCookieNotHttpOnly.java:63:37:63:115 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie |
| SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | semmle.label | "session-access-key" : String |
| SensitiveCookieNotHttpOnly.java:64:25:64:39 | accessKeyCookie : NewCookie | semmle.label | accessKeyCookie : NewCookie |
| SensitiveCookieNotHttpOnly.java:64:25:64:50 | toString(...) : String | semmle.label | toString(...) : String |
| SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | semmle.label | keyStr |
| SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | semmle.label | "token=" : String |
| SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | semmle.label | ... + ... : String |
| SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | semmle.label | ... + ... : String |
| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | semmle.label | secString |
| SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | semmle.label | "Presto-UI-Token" : String |
| SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie | semmle.label | new Cookie(...) : Cookie |
| SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String | semmle.label | PRESTO_UI_COOKIE : String |
| SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | semmle.label | cookie : Cookie |
| SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | semmle.label | createAuthenticationCookie(...) : Cookie |
| SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | semmle.label | cookie |
problems
| SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" | This sensitive cookie |
| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" | This sensitive cookie |
| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... | This sensitive cookie |
| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | This sensitive cookie |
| SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" | This sensitive cookie |
| SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" | This sensitive cookie |
| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" | This sensitive cookie |
| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... | This sensitive cookie |
| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... | This sensitive cookie |
| SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" | This sensitive cookie |
subpaths

View File

@@ -1,164 +0,0 @@
import java.io.IOException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import javax.ws.rs.core.NewCookie;
import org.springframework.security.web.csrf.CsrfToken;
class SensitiveCookieNotHttpOnly {
// GOOD - Tests adding a sensitive cookie with the `HttpOnly` flag set.
public void addCookie(String jwt_token, HttpServletRequest request, HttpServletResponse response) {
Cookie jwtCookie = new Cookie("jwt_token", jwt_token);
jwtCookie.setPath("/");
jwtCookie.setMaxAge(3600*24*7);
jwtCookie.setHttpOnly(true);
response.addCookie(jwtCookie);
}
// BAD - Tests adding a sensitive cookie without the `HttpOnly` flag set.
public void addCookie2(String jwt_token, String userId, HttpServletRequest request, HttpServletResponse response) {
String tokenCookieStr = "jwt_token";
Cookie jwtCookie = new Cookie(tokenCookieStr, jwt_token);
Cookie userIdCookie = new Cookie("user_id", userId);
jwtCookie.setPath("/");
userIdCookie.setPath("/");
jwtCookie.setMaxAge(3600*24*7);
userIdCookie.setMaxAge(3600*24*7);
response.addCookie(jwtCookie);
response.addCookie(userIdCookie);
}
// GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set.
public void addCookie3(String authId, HttpServletRequest request, HttpServletResponse response) {
response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure");
}
// BAD - Tests set a sensitive cookie header without the `HttpOnly` flag set.
public void addCookie4(String authId, HttpServletRequest request, HttpServletResponse response) {
response.addHeader("Set-Cookie", "token=" +authId + ";Secure");
}
// GOOD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` with the `HttpOnly` flag set through string concatenation.
public void addCookie5(String accessKey, HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Set-Cookie", new NewCookie("session-access-key", accessKey, "/", null, null, 0, true) + ";HttpOnly");
}
// BAD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` without the `HttpOnly` flag set.
public void addCookie6(String accessKey, HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Set-Cookie", new NewCookie("session-access-key", accessKey, "/", null, null, 0, true).toString());
}
// GOOD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` with the `HttpOnly` flag set through the constructor.
public void addCookie7(String accessKey, HttpServletRequest request, HttpServletResponse response) {
NewCookie accessKeyCookie = new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true);
response.setHeader("Set-Cookie", accessKeyCookie.toString());
}
// BAD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` without the `HttpOnly` flag set.
public void addCookie8(String accessKey, HttpServletRequest request, HttpServletResponse response) {
NewCookie accessKeyCookie = new NewCookie("session-access-key", accessKey, "/", null, 0, null, 86400, true);
String keyStr = accessKeyCookie.toString();
response.setHeader("Set-Cookie", keyStr);
}
// BAD - Tests set a sensitive cookie header using a variable without the `HttpOnly` flag set.
public void addCookie9(String authId, HttpServletRequest request, HttpServletResponse response) {
String secString = "token=" +authId + ";Secure";
response.addHeader("Set-Cookie", secString);
}
// GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set using `String.format(...)`.
public void addCookie10(HttpServletRequest request, HttpServletResponse response) {
response.addHeader("SET-COOKIE", String.format("%s=%s;HttpOnly", "sessionkey", request.getSession().getAttribute("sessionkey")));
}
public Cookie createHttpOnlyAuthenticationCookie(HttpServletRequest request, String jwt) {
String PRESTO_UI_COOKIE = "Presto-UI-Token";
Cookie cookie = new Cookie(PRESTO_UI_COOKIE, jwt);
cookie.setHttpOnly(true);
cookie.setPath("/ui");
return cookie;
}
public Cookie createAuthenticationCookie(HttpServletRequest request, String jwt) {
String PRESTO_UI_COOKIE = "Presto-UI-Token";
Cookie cookie = new Cookie(PRESTO_UI_COOKIE, jwt);
cookie.setPath("/ui");
return cookie;
}
public Cookie removeAuthenticationCookie(HttpServletRequest request, String jwt) {
String PRESTO_UI_COOKIE = "Presto-UI-Token";
Cookie cookie = new Cookie(PRESTO_UI_COOKIE, jwt);
cookie.setPath("/ui");
cookie.setMaxAge(0);
return cookie;
}
// GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set using a wrapper method.
public void addCookie11(HttpServletRequest request, HttpServletResponse response, String jwt) {
Cookie cookie = createHttpOnlyAuthenticationCookie(request, jwt);
response.addCookie(cookie);
}
// BAD - Tests set a sensitive cookie header without the `HttpOnly` flag set using a wrapper method.
public void addCookie12(HttpServletRequest request, HttpServletResponse response, String jwt) {
Cookie cookie = createAuthenticationCookie(request, jwt);
response.addCookie(cookie);
}
// GOOD - Tests remove a sensitive cookie header without the `HttpOnly` flag set using a wrapper method.
public void addCookie13(HttpServletRequest request, HttpServletResponse response, String jwt) {
Cookie cookie = removeAuthenticationCookie(request, jwt);
response.addCookie(cookie);
}
private Cookie createCookie(String name, String value, Boolean httpOnly){
Cookie cookie = null;
cookie = new Cookie(name, value);
cookie.setDomain("/");
cookie.setHttpOnly(httpOnly);
//for production https
cookie.setSecure(true);
cookie.setMaxAge(60*60*24*30);
cookie.setPath("/");
return cookie;
}
// GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set through a boolean variable using a wrapper method.
public void addCookie14(HttpServletRequest request, HttpServletResponse response, String refreshToken) {
response.addCookie(createCookie("refresh_token", refreshToken, true));
}
// BAD (but not detected) - Tests set a sensitive cookie header with the `HttpOnly` flag not set through a boolean variable using a wrapper method.
// This example is missed because the `cookie.setHttpOnly` call in `createCookie` is thought to maybe set the HTTP-only flag, and the `cookie`
// object flows to this `addCookie` call.
public void addCookie15(HttpServletRequest request, HttpServletResponse response, String refreshToken) {
response.addCookie(createCookie("refresh_token", refreshToken, false));
}
// GOOD - CSRF token doesn't need to have the `HttpOnly` flag set.
public void addCsrfCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Spring put the CSRF token in session attribute "_csrf"
CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
// Send the cookie only if the token has changed
String actualToken = request.getHeader("X-CSRF-TOKEN");
if (actualToken == null || !actualToken.equals(csrfToken.getToken())) {
// Session cookie that can be used by AngularJS
String pCookieName = "CSRF-TOKEN";
Cookie cookie = new Cookie(pCookieName, csrfToken.getToken());
cookie.setMaxAge(-1);
cookie.setHttpOnly(false);
cookie.setPath("/");
response.addCookie(cookie);
}
}
}

View File

@@ -1,2 +0,0 @@
query: experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql
postprocess: utils/test/PrettyPrintModels.ql

View File

@@ -1 +0,0 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jsr311-api-1.1.1:${testdir}/../../../../stubs/springframework-5.8.x