mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Remove experimental query and tests
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
query: experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql
|
||||
postprocess: utils/test/PrettyPrintModels.ql
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user