mirror of
https://github.com/github/codeql.git
synced 2026-05-13 02:39:26 +02:00
Merge pull request #7721 from erik-krogh/CWE-1275
JS: add a js/samesite-none-cookie cookie
This commit is contained in:
@@ -27,6 +27,12 @@ module CookieWrites {
|
||||
*/
|
||||
abstract predicate isSensitive();
|
||||
|
||||
/**
|
||||
* Gets the SameSite attribute of the cookie if present.
|
||||
* Either "Strict", "Lax" or "None".
|
||||
*/
|
||||
abstract string getSameSite();
|
||||
|
||||
/**
|
||||
* Holds if the cookie write happens on a server, i.e. the `httpOnly` flag is relevant.
|
||||
*/
|
||||
@@ -95,6 +101,31 @@ private predicate hasCookieAttribute(string s, string attribute) {
|
||||
s.regexpMatch("(?i).*;\\s*" + attribute + "\\b\\s*;?.*$")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for a `Set-Cookie` header attribute.
|
||||
*/
|
||||
bindingset[s, attribute]
|
||||
private string getCookieValue(string s, string attribute) {
|
||||
result = s.regexpCapture("(?i).*;\\s*" + attribute + "=(\\w+)\\b\\s*;?.*$", 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "SameSite" value for a given `node`.
|
||||
* Converts boolean values to the corresponding string value.
|
||||
*
|
||||
* Not all libraries support boolean values for the `SameSite` attribute,
|
||||
* but here we assume that they do.
|
||||
*/
|
||||
private string getSameSiteValue(DataFlow::Node node) {
|
||||
node.mayHaveStringValue(result)
|
||||
or
|
||||
node.mayHaveBooleanValue(true) and
|
||||
result = "Strict"
|
||||
or
|
||||
node.mayHaveBooleanValue(false) and
|
||||
result = "Lax"
|
||||
}
|
||||
|
||||
/**
|
||||
* A model of the `js-cookie` library (https://github.com/js-cookie/js-cookie).
|
||||
*/
|
||||
@@ -105,7 +136,9 @@ private module JsCookie {
|
||||
DataFlow::CallNode libMemberCall(string name) {
|
||||
result = DataFlow::globalVarRef("Cookie").getAMemberCall(name) or
|
||||
result = DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict").getAMemberCall(name) or
|
||||
result = DataFlow::moduleMember("js-cookie", name).getACall()
|
||||
result = DataFlow::moduleMember("js-cookie", name).getACall() or
|
||||
// es-cookie behaves basically the same as js-cookie
|
||||
result = DataFlow::moduleMember("es-cookie", name).getACall()
|
||||
}
|
||||
|
||||
class ReadAccess extends PersistentReadAccess, DataFlow::CallNode {
|
||||
@@ -132,6 +165,10 @@ private module JsCookie {
|
||||
}
|
||||
|
||||
override predicate isSensitive() { canHaveSensitiveCookie(this.getArgument(0)) }
|
||||
|
||||
override string getSameSite() {
|
||||
result = getSameSiteValue(this.getOptionArgument(2, "sameSite"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +210,15 @@ private module BrowserCookies {
|
||||
}
|
||||
|
||||
override predicate isSensitive() { canHaveSensitiveCookie(this.getArgument(0)) }
|
||||
|
||||
override string getSameSite() {
|
||||
result = getSameSiteValue(this.getOptionArgument(2, "samesite"))
|
||||
or
|
||||
// or, an explicit default has been set
|
||||
DataFlow::moduleMember("browser-cookies", "defaults")
|
||||
.getAPropertyWrite("samesite")
|
||||
.mayHaveStringValue(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +257,10 @@ private module LibCookie {
|
||||
}
|
||||
|
||||
override predicate isSensitive() { canHaveSensitiveCookie(this.getArgument(0)) }
|
||||
|
||||
override string getSameSite() {
|
||||
result = getSameSiteValue(this.getOptionArgument(2, "sameSite"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,6 +292,10 @@ private module ExpressCookies {
|
||||
not value.mayHaveBooleanValue(false) // anything but `false` is accepted as being maybe true
|
||||
)
|
||||
}
|
||||
|
||||
override string getSameSite() {
|
||||
result = getSameSiteValue(this.getOptionArgument(2, "sameSite"))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,6 +322,8 @@ private module ExpressCookies {
|
||||
// A cookie is httpOnly if the `httpOnly` flag is not explicitly set to `false`.
|
||||
not this.getCookieFlagValue(CookieWrites::httpOnly()).mayHaveBooleanValue(false)
|
||||
}
|
||||
|
||||
override string getSameSite() { result = getSameSiteValue(this.getCookieFlagValue("sameSite")) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,6 +353,8 @@ private module ExpressCookies {
|
||||
// A cookie is httpOnly if the `httpOnly` flag is not explicitly set to `false`.
|
||||
not this.getCookieFlagValue(CookieWrites::httpOnly()).mayHaveBooleanValue(false)
|
||||
}
|
||||
|
||||
override string getSameSite() { result = getSameSiteValue(this.getCookieFlagValue("sameSite")) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,6 +397,8 @@ private class HTTPCookieWrite extends CookieWrites::CookieWrite {
|
||||
}
|
||||
|
||||
override predicate isSensitive() { canHaveSensitiveCookie(this) }
|
||||
|
||||
override string getSameSite() { result = getCookieValue(header, "SameSite") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,4 +425,6 @@ private class DocumentCookieWrite extends CookieWrites::ClientSideCookieWrite {
|
||||
}
|
||||
|
||||
override predicate isSensitive() { canHaveSensitiveCookie(write.getRhs()) }
|
||||
|
||||
override string getSameSite() { result = getCookieValue(cookie, "SameSite") }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user