mirror of
https://github.com/github/codeql.git
synced 2026-04-26 01:05:15 +02:00
Implement cookie attributes for cases in which a raw header is set
This commit is contained in:
@@ -1250,17 +1250,70 @@ module Http {
|
||||
/**
|
||||
* Holds if the `Secure` flag of the cookie is known to have a value of `b`.
|
||||
*/
|
||||
predicate hasSecureFlag(boolean b) { none() }
|
||||
predicate hasSecureFlag(boolean b) {
|
||||
exists(this.getHeaderArg()) and
|
||||
(
|
||||
exists(StringLiteral sl |
|
||||
sl.getText().regexpMatch("(?i).*;\\s*secure;.*") and
|
||||
TaintTracking::localTaint(DataFlow::exprNode(sl), this.getHeaderArg()) and
|
||||
b = true
|
||||
)
|
||||
or
|
||||
exists(StringLiteral sl |
|
||||
not sl.getText().regexpMatch("(?i).*;\\s*secure;.*") and
|
||||
DataFlow::localFlow(DataFlow::exprNode(sl), this.getHeaderArg()) and
|
||||
b = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `HttpOnly` flag of the cookie is known to have a value of `b`.
|
||||
*/
|
||||
predicate hasHttpOnlyFlag(boolean b) { none() }
|
||||
predicate hasHttpOnlyFlag(boolean b) {
|
||||
exists(this.getHeaderArg()) and
|
||||
(
|
||||
exists(StringLiteral sl |
|
||||
sl.getText().regexpMatch("(?i).*;\\s*httponly;.*") and
|
||||
TaintTracking::localTaint(DataFlow::exprNode(sl), this.getHeaderArg()) and
|
||||
b = true
|
||||
)
|
||||
or
|
||||
exists(StringLiteral sl |
|
||||
not sl.getText().regexpMatch("(?i).*;\\s*httponly;.*") and
|
||||
DataFlow::localFlow(DataFlow::exprNode(sl), this.getHeaderArg()) and
|
||||
b = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `SameSite` flag of the cookie is known to have a value of `b`.
|
||||
*/
|
||||
predicate hasSameSiteFlag(boolean b) { none() }
|
||||
// TODO: b could be a newtype with 3 values indicating Strict,Lax,or None
|
||||
// currently, Strict and Lax are represented with true and None is represented with false.
|
||||
predicate hasSameSiteFlag(boolean b) {
|
||||
exists(this.getHeaderArg()) and
|
||||
(
|
||||
exists(StringLiteral sl |
|
||||
sl.getText().regexpMatch("(?i).*;\\s*samesite=(strict|lax);.*") and
|
||||
TaintTracking::localTaint(DataFlow::exprNode(sl), this.getHeaderArg()) and
|
||||
b = true
|
||||
)
|
||||
or
|
||||
exists(StringLiteral sl |
|
||||
sl.getText().regexpMatch("(?i).*;\\s*samesite=none;.*") and
|
||||
TaintTracking::localTaint(DataFlow::exprNode(sl), this.getHeaderArg()) and
|
||||
b = false
|
||||
)
|
||||
or
|
||||
exists(StringLiteral sl |
|
||||
not sl.getText().regexpMatch("(?i).*;\\s*samesite=(strict|lax|none);.*") and
|
||||
DataFlow::localFlow(DataFlow::exprNode(sl), this.getHeaderArg()) and
|
||||
b = true // Lax is the default
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import experimental.semmle.python.Concepts
|
||||
import semmle.python.Concepts
|
||||
import experimental.semmle.python.CookieHeader
|
||||
|
||||
from Http::Server::CookieWrite cookie, string alert
|
||||
where
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* Temporary: provides a class to extend current cookies to header declarations
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
import experimental.semmle.python.Concepts
|
||||
import semmle.python.Concepts
|
||||
|
||||
/**
|
||||
* Gets a header setting a cookie.
|
||||
*
|
||||
* Given the following example:
|
||||
*
|
||||
* ```py
|
||||
* @app.route("/")
|
||||
* def flask_make_response():
|
||||
* resp = make_response("")
|
||||
* resp.headers['Set-Cookie'] = "name=value; Secure;"
|
||||
* return resp
|
||||
* ```
|
||||
*
|
||||
* * `this` would be `resp.headers['Set-Cookie'] = "name=value; Secure;"`.
|
||||
* * `isSecure()` predicate would succeed.
|
||||
* * `isHttpOnly()` predicate would fail.
|
||||
* * `isSameSite()` predicate would fail.
|
||||
* * `getName()` and `getValue()` results would be `"name=value; Secure;"`.
|
||||
*/
|
||||
class CookieHeader extends Http::Server::CookieWrite::Range instanceof Http::Server::ResponseHeaderWrite
|
||||
{
|
||||
CookieHeader() {
|
||||
exists(StringLiteral str |
|
||||
str.getText() = "Set-Cookie" and
|
||||
DataFlow::exprNode(str)
|
||||
.(DataFlow::LocalSourceNode)
|
||||
.flowsTo(this.(Http::Server::ResponseHeaderWrite).getNameArg())
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasSecureFlag(boolean b) {
|
||||
if
|
||||
exists(StringLiteral str |
|
||||
str.getText().regexpMatch(".*; *Secure;.*") and
|
||||
DataFlow::exprNode(str)
|
||||
.(DataFlow::LocalSourceNode)
|
||||
.flowsTo(this.(Http::Server::ResponseHeaderWrite).getValueArg())
|
||||
)
|
||||
then b = true
|
||||
else b = false
|
||||
}
|
||||
|
||||
override predicate hasHttpOnlyFlag(boolean b) {
|
||||
if
|
||||
exists(StringLiteral str |
|
||||
str.getText().regexpMatch(".*; *HttpOnly;.*") and
|
||||
DataFlow::exprNode(str)
|
||||
.(DataFlow::LocalSourceNode)
|
||||
.flowsTo(this.(Http::Server::ResponseHeaderWrite).getValueArg())
|
||||
)
|
||||
then b = true
|
||||
else b = false
|
||||
}
|
||||
|
||||
override predicate hasSameSiteFlag(boolean b) {
|
||||
if
|
||||
exists(StringLiteral str |
|
||||
str.getText().regexpMatch(".*; *SameSite=(Strict|Lax);.*") and
|
||||
DataFlow::exprNode(str)
|
||||
.(DataFlow::LocalSourceNode)
|
||||
.flowsTo(this.(Http::Server::ResponseHeaderWrite).getValueArg())
|
||||
)
|
||||
then b = true
|
||||
else b = false
|
||||
}
|
||||
|
||||
override DataFlow::Node getNameArg() {
|
||||
result = this.(Http::Server::ResponseHeaderWrite).getValueArg()
|
||||
}
|
||||
|
||||
override DataFlow::Node getValueArg() {
|
||||
result = this.(Http::Server::ResponseHeaderWrite).getValueArg()
|
||||
}
|
||||
|
||||
override DataFlow::Node getHeaderArg() { none() }
|
||||
}
|
||||
Reference in New Issue
Block a user