Skip to content

Commit 90e87a1

Browse files
Factor each framework implementation of the cookie parameters to a common concept
1 parent c7f9095 commit 90e87a1

File tree

8 files changed

+58
-325
lines changed

8 files changed

+58
-325
lines changed

python/ql/lib/semmle/python/Concepts.qll

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,57 @@ module Http {
12201220
predicate hasSameSiteAttribute(CookieWrite::SameSiteValue v) { super.hasSameSiteAttribute(v) }
12211221
}
12221222

1223+
/**
1224+
* A dataflow call node to a method that sets a cookie in an http response,
1225+
* and has common keyword arguments `secure`, `httponly`, and `samesite` to set the attributes of the cookie.
1226+
*/
1227+
abstract class SetCookieCall extends CookieWrite::Range, DataFlow::CallCfgNode {
1228+
override predicate hasSecureFlag(boolean b) {
1229+
super.hasSecureFlag(b)
1230+
or
1231+
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("secure") |
1232+
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
1233+
b = bool.booleanValue()
1234+
)
1235+
or
1236+
not exists(this.getArgByName("secure")) and
1237+
b = false
1238+
}
1239+
1240+
override predicate hasHttpOnlyFlag(boolean b) {
1241+
super.hasHttpOnlyFlag(b)
1242+
or
1243+
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("httponly") |
1244+
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
1245+
b = bool.booleanValue()
1246+
)
1247+
or
1248+
not exists(this.getArgByName("httponly")) and
1249+
b = false
1250+
}
1251+
1252+
override predicate hasSameSiteAttribute(CookieWrite::SameSiteValue v) {
1253+
super.hasSameSiteAttribute(v)
1254+
or
1255+
exists(DataFlow::Node arg, StringLiteral str | arg = this.getArgByName("samesite") |
1256+
DataFlow::localFlow(DataFlow::exprNode(str), arg) and
1257+
(
1258+
str.getText().toLowerCase() = "strict" and
1259+
v instanceof CookieWrite::SameSiteStrict
1260+
or
1261+
str.getText().toLowerCase() = "lax" and
1262+
v instanceof CookieWrite::SameSiteLax
1263+
or
1264+
str.getText().toLowerCase() = "none" and
1265+
v instanceof CookieWrite::SameSiteNone
1266+
)
1267+
)
1268+
or
1269+
not exists(this.getArgByName("samesite")) and
1270+
v instanceof CookieWrite::SameSiteLax // Lax is the default
1271+
}
1272+
}
1273+
12231274
/** Provides a class for modeling new cookie writes on HTTP responses. */
12241275
module CookieWrite {
12251276
/**

python/ql/lib/semmle/python/frameworks/Aiohttp.qll

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -653,8 +653,7 @@ module AiohttpWebModel {
653653
/**
654654
* A call to `set_cookie` on a HTTP Response.
655655
*/
656-
class AiohttpResponseSetCookieCall extends Http::Server::CookieWrite::Range, DataFlow::CallCfgNode
657-
{
656+
class AiohttpResponseSetCookieCall extends Http::Server::SetCookieCall {
658657
AiohttpResponseSetCookieCall() {
659658
this = aiohttpResponseInstance().getMember("set_cookie").getACall()
660659
}
@@ -664,51 +663,6 @@ module AiohttpWebModel {
664663
override DataFlow::Node getNameArg() { result in [this.getArg(0), this.getArgByName("name")] }
665664

666665
override DataFlow::Node getValueArg() { result in [this.getArg(1), this.getArgByName("value")] }
667-
668-
override predicate hasSecureFlag(boolean b) {
669-
super.hasSecureFlag(b)
670-
or
671-
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("secure") |
672-
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
673-
b = bool.booleanValue()
674-
)
675-
or
676-
not exists(this.getArgByName("secure")) and
677-
b = false
678-
}
679-
680-
override predicate hasHttpOnlyFlag(boolean b) {
681-
super.hasHttpOnlyFlag(b)
682-
or
683-
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("httponly") |
684-
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
685-
b = bool.booleanValue()
686-
)
687-
or
688-
not exists(this.getArgByName("httponly")) and
689-
b = false
690-
}
691-
692-
override predicate hasSameSiteAttribute(Http::Server::CookieWrite::SameSiteValue v) {
693-
super.hasSameSiteAttribute(v)
694-
or
695-
exists(DataFlow::Node arg, StringLiteral str | arg = this.getArgByName("samesite") |
696-
DataFlow::localFlow(DataFlow::exprNode(str), arg) and
697-
(
698-
str.getText().toLowerCase() = "strict" and
699-
v instanceof Http::Server::CookieWrite::SameSiteStrict
700-
or
701-
str.getText().toLowerCase() = "lax" and
702-
v instanceof Http::Server::CookieWrite::SameSiteLax
703-
or
704-
str.getText().toLowerCase() = "none" and
705-
v instanceof Http::Server::CookieWrite::SameSiteNone
706-
)
707-
)
708-
or
709-
not exists(this.getArgByName("samesite")) and
710-
v instanceof Http::Server::CookieWrite::SameSiteLax // Lax is the default
711-
}
712666
}
713667

714668
/**

python/ql/lib/semmle/python/frameworks/Django.qll

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2170,7 +2170,7 @@ module PrivateDjango {
21702170
/**
21712171
* A call to `set_cookie` on a HTTP Response.
21722172
*/
2173-
class DjangoResponseSetCookieCall extends Http::Server::CookieWrite::Range,
2173+
class DjangoResponseSetCookieCall extends Http::Server::SetCookieCall,
21742174
DataFlow::MethodCallNode
21752175
{
21762176
DjangoResponseSetCookieCall() {
@@ -2186,51 +2186,6 @@ module PrivateDjango {
21862186
override DataFlow::Node getValueArg() {
21872187
result in [this.getArg(1), this.getArgByName("value")]
21882188
}
2189-
2190-
override predicate hasSecureFlag(boolean b) {
2191-
super.hasSecureFlag(b)
2192-
or
2193-
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("secure") |
2194-
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
2195-
b = bool.booleanValue()
2196-
)
2197-
or
2198-
not exists(this.getArgByName("secure")) and
2199-
b = false
2200-
}
2201-
2202-
override predicate hasHttpOnlyFlag(boolean b) {
2203-
super.hasHttpOnlyFlag(b)
2204-
or
2205-
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("httponly") |
2206-
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
2207-
b = bool.booleanValue()
2208-
)
2209-
or
2210-
not exists(this.getArgByName("httponly")) and
2211-
b = false
2212-
}
2213-
2214-
override predicate hasSameSiteAttribute(Http::Server::CookieWrite::SameSiteValue v) {
2215-
super.hasSameSiteAttribute(v)
2216-
or
2217-
exists(DataFlow::Node arg, StringLiteral str | arg = this.getArgByName("samesite") |
2218-
DataFlow::localFlow(DataFlow::exprNode(str), arg) and
2219-
(
2220-
str.getText().toLowerCase() = "strict" and
2221-
v instanceof Http::Server::CookieWrite::SameSiteStrict
2222-
or
2223-
str.getText().toLowerCase() = "lax" and
2224-
v instanceof Http::Server::CookieWrite::SameSiteLax
2225-
or
2226-
str.getText().toLowerCase() = "none" and
2227-
v instanceof Http::Server::CookieWrite::SameSiteNone
2228-
)
2229-
)
2230-
or
2231-
not exists(this.getArgByName("samesite")) and
2232-
v instanceof Http::Server::CookieWrite::SameSiteLax // Lax is the default
2233-
}
22342189
}
22352190

22362191
/**

python/ql/lib/semmle/python/frameworks/FastApi.qll

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ module FastApi {
348348
/**
349349
* A call to `set_cookie` on a FastAPI Response.
350350
*/
351-
private class SetCookieCall extends Http::Server::CookieWrite::Range, DataFlow::MethodCallNode {
351+
private class SetCookieCall extends Http::Server::SetCookieCall, DataFlow::MethodCallNode {
352352
SetCookieCall() { this.calls(instance(), "set_cookie") }
353353

354354
override DataFlow::Node getHeaderArg() { none() }
@@ -358,51 +358,6 @@ module FastApi {
358358
override DataFlow::Node getValueArg() {
359359
result in [this.getArg(1), this.getArgByName("value")]
360360
}
361-
362-
override predicate hasSecureFlag(boolean b) {
363-
super.hasSecureFlag(b)
364-
or
365-
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("secure") |
366-
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
367-
b = bool.booleanValue()
368-
)
369-
or
370-
not exists(this.getArgByName("secure")) and
371-
b = false
372-
}
373-
374-
override predicate hasHttpOnlyFlag(boolean b) {
375-
super.hasHttpOnlyFlag(b)
376-
or
377-
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("httponly") |
378-
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
379-
b = bool.booleanValue()
380-
)
381-
or
382-
not exists(this.getArgByName("httponly")) and
383-
b = false
384-
}
385-
386-
override predicate hasSameSiteAttribute(Http::Server::CookieWrite::SameSiteValue v) {
387-
super.hasSameSiteAttribute(v)
388-
or
389-
exists(DataFlow::Node arg, StringLiteral str | arg = this.getArgByName("samesite") |
390-
DataFlow::localFlow(DataFlow::exprNode(str), arg) and
391-
(
392-
str.getText().toLowerCase() = "strict" and
393-
v instanceof Http::Server::CookieWrite::SameSiteStrict
394-
or
395-
str.getText().toLowerCase() = "lax" and
396-
v instanceof Http::Server::CookieWrite::SameSiteLax
397-
or
398-
str.getText().toLowerCase() = "none" and
399-
v instanceof Http::Server::CookieWrite::SameSiteNone
400-
)
401-
)
402-
or
403-
not exists(this.getArgByName("samesite")) and
404-
v instanceof Http::Server::CookieWrite::SameSiteLax // Lax is the default
405-
}
406361
}
407362

408363
/**

python/ql/lib/semmle/python/frameworks/Flask.qll

Lines changed: 1 addition & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -583,61 +583,14 @@ module Flask {
583583
*
584584
* See https://flask.palletsprojects.com/en/2.0.x/api/#flask.Response.set_cookie
585585
*/
586-
class FlaskResponseSetCookieCall extends Http::Server::CookieWrite::Range,
587-
DataFlow::MethodCallNode
588-
{
586+
class FlaskResponseSetCookieCall extends Http::Server::SetCookieCall, DataFlow::MethodCallNode {
589587
FlaskResponseSetCookieCall() { this.calls(Flask::Response::instance(), "set_cookie") }
590588

591589
override DataFlow::Node getHeaderArg() { none() }
592590

593591
override DataFlow::Node getNameArg() { result in [this.getArg(0), this.getArgByName("key")] }
594592

595593
override DataFlow::Node getValueArg() { result in [this.getArg(1), this.getArgByName("value")] }
596-
597-
override predicate hasSecureFlag(boolean b) {
598-
super.hasSecureFlag(b)
599-
or
600-
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("secure") |
601-
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
602-
b = bool.booleanValue()
603-
)
604-
or
605-
not exists(this.getArgByName("secure")) and
606-
b = false
607-
}
608-
609-
override predicate hasHttpOnlyFlag(boolean b) {
610-
super.hasHttpOnlyFlag(b)
611-
or
612-
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("httponly") |
613-
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
614-
b = bool.booleanValue()
615-
)
616-
or
617-
not exists(this.getArgByName("httponly")) and
618-
b = false
619-
}
620-
621-
override predicate hasSameSiteAttribute(Http::Server::CookieWrite::SameSiteValue v) {
622-
super.hasSameSiteAttribute(v)
623-
or
624-
exists(DataFlow::Node arg, StringLiteral str | arg = this.getArgByName("samesite") |
625-
DataFlow::localFlow(DataFlow::exprNode(str), arg) and
626-
(
627-
str.getText().toLowerCase() = "strict" and
628-
v instanceof Http::Server::CookieWrite::SameSiteStrict
629-
or
630-
str.getText().toLowerCase() = "lax" and
631-
v instanceof Http::Server::CookieWrite::SameSiteLax
632-
or
633-
str.getText().toLowerCase() = "none" and
634-
v instanceof Http::Server::CookieWrite::SameSiteNone
635-
)
636-
)
637-
or
638-
not exists(this.getArgByName("samesite")) and
639-
v instanceof Http::Server::CookieWrite::SameSiteLax // Lax is the default
640-
}
641594
}
642595

643596
/**

python/ql/lib/semmle/python/frameworks/Pyramid.qll

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ module Pyramid {
255255
}
256256

257257
/** A call to `response.set_cookie`. */
258-
private class SetCookieCall extends Http::Server::CookieWrite::Range, DataFlow::MethodCallNode {
258+
private class SetCookieCall extends Http::Server::SetCookieCall, DataFlow::MethodCallNode {
259259
SetCookieCall() { this.calls(instance(), "set_cookie") }
260260

261261
override DataFlow::Node getHeaderArg() { none() }
@@ -265,51 +265,6 @@ module Pyramid {
265265
override DataFlow::Node getValueArg() {
266266
result = [this.getArg(1), this.getArgByName("value")]
267267
}
268-
269-
override predicate hasSecureFlag(boolean b) {
270-
super.hasSecureFlag(b)
271-
or
272-
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("secure") |
273-
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
274-
b = bool.booleanValue()
275-
)
276-
or
277-
not exists(this.getArgByName("secure")) and
278-
b = false
279-
}
280-
281-
override predicate hasHttpOnlyFlag(boolean b) {
282-
super.hasHttpOnlyFlag(b)
283-
or
284-
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("httponly") |
285-
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
286-
b = bool.booleanValue()
287-
)
288-
or
289-
not exists(this.getArgByName("httponly")) and
290-
b = false
291-
}
292-
293-
override predicate hasSameSiteAttribute(Http::Server::CookieWrite::SameSiteValue v) {
294-
super.hasSameSiteAttribute(v)
295-
or
296-
exists(DataFlow::Node arg, StringLiteral str | arg = this.getArgByName("samesite") |
297-
DataFlow::localFlow(DataFlow::exprNode(str), arg) and
298-
(
299-
str.getText().toLowerCase() = "strict" and
300-
v instanceof Http::Server::CookieWrite::SameSiteStrict
301-
or
302-
str.getText().toLowerCase() = "lax" and
303-
v instanceof Http::Server::CookieWrite::SameSiteLax
304-
or
305-
str.getText().toLowerCase() = "none" and
306-
v instanceof Http::Server::CookieWrite::SameSiteNone
307-
)
308-
)
309-
or
310-
not exists(this.getArgByName("samesite")) and
311-
v instanceof Http::Server::CookieWrite::SameSiteLax // Lax is the default
312-
}
313268
}
314269
}
315270

0 commit comments

Comments
 (0)