Skip to content

Commit 9340d65

Browse files
committed
Python: Model CookieWrite for django
1 parent 930ed0a commit 9340d65

File tree

2 files changed

+73
-3
lines changed

2 files changed

+73
-3
lines changed

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

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,74 @@ private module PrivateDjango {
13641364

13651365
override string getMimetypeDefault() { result = instance.getMimetypeDefault() }
13661366
}
1367+
1368+
/**
1369+
* A call to `set_cookie` on a HTTP Response.
1370+
*/
1371+
class DjangoResponseSetCookieCall extends HTTP::Server::CookieWrite::Range,
1372+
DataFlow::MethodCallNode {
1373+
DjangoResponseSetCookieCall() {
1374+
this.calls(django::http::response::HttpResponse::instance(), "set_cookie")
1375+
}
1376+
1377+
override DataFlow::Node getHeaderArg() { none() }
1378+
1379+
override DataFlow::Node getNameArg() {
1380+
result in [this.getArg(0), this.getArgByName("key")]
1381+
}
1382+
1383+
override DataFlow::Node getValueArg() {
1384+
result in [this.getArg(1), this.getArgByName("value")]
1385+
}
1386+
}
1387+
1388+
/**
1389+
* A call to `delete_cookie` on a HTTP Response.
1390+
*/
1391+
class DjangoResponseDeleteCookieCall extends HTTP::Server::CookieWrite::Range,
1392+
DataFlow::MethodCallNode {
1393+
DjangoResponseDeleteCookieCall() {
1394+
this.calls(django::http::response::HttpResponse::instance(), "delete_cookie")
1395+
}
1396+
1397+
override DataFlow::Node getHeaderArg() { none() }
1398+
1399+
override DataFlow::Node getNameArg() {
1400+
result in [this.getArg(0), this.getArgByName("key")]
1401+
}
1402+
1403+
override DataFlow::Node getValueArg() { none() }
1404+
}
1405+
1406+
/**
1407+
* A dict-like write to an item of the `cookies` attribute on a HTTP response, such as
1408+
* `response.cookies[name] = value`.
1409+
*/
1410+
class DjangoResponseCookieSubscriptWrite extends HTTP::Server::CookieWrite::Range {
1411+
DataFlow::Node index;
1412+
DataFlow::Node value;
1413+
1414+
DjangoResponseCookieSubscriptWrite() {
1415+
exists(Assign assign, Subscript subscript, DataFlow::AttrRead cookieLookup |
1416+
// there doesn't seem to be any _good_ choice for `this`, so just picking the
1417+
// whole subscript...
1418+
this.asExpr() = subscript
1419+
|
1420+
cookieLookup.getAttributeName() = "cookies" and
1421+
cookieLookup.getObject() = django::http::response::HttpResponse::instance() and
1422+
assign.getATarget() = subscript and
1423+
cookieLookup.flowsTo(DataFlow::exprNode(subscript.getObject())) and
1424+
index.asExpr() = subscript.getIndex() and
1425+
value.asExpr() = assign.getValue()
1426+
)
1427+
}
1428+
1429+
override DataFlow::Node getHeaderArg() { none() }
1430+
1431+
override DataFlow::Node getNameArg() { result = index }
1432+
1433+
override DataFlow::Node getValueArg() { result = value }
1434+
}
13671435
}
13681436
}
13691437

python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,10 @@ def safe__custom_json_response(request):
110110

111111
def setting_cookie(request):
112112
resp = HttpResponse() # $ HttpResponse mimetype=text/html
113-
resp.set_cookie("key", "value") # $ MISSING: CookieWrite CookieName="key" CookieValue="value"
114-
resp.set_cookie(key="key", value="value") # $ MISSING: CookieWrite CookieName="key" CookieValue="value"
113+
resp.set_cookie("key", "value") # $ CookieWrite CookieName="key" CookieValue="value"
114+
resp.set_cookie(key="key", value="value") # $ CookieWrite CookieName="key" CookieValue="value"
115115
resp.headers["Set-Cookie"] = "key2=value2" # $ MISSING: CookieWrite CookieRawHeader="key2=value2"
116-
resp.cookies["key3"] = "value3" # $ MISSING: CookieWrite CookieName="key3" CookieValue="value3"
116+
resp.cookies["key3"] = "value3" # $ CookieWrite CookieName="key3" CookieValue="value3"
117+
resp.delete_cookie("key4") # $ CookieWrite CookieName="key4"
118+
resp.delete_cookie(key="key4") # $ CookieWrite CookieName="key4"
117119
return resp

0 commit comments

Comments
 (0)