Skip to content

Commit 8679806

Browse files
committed
Python: Model tainted attributes of django HttpRequest
1 parent a3cdbf2 commit 8679806

File tree

2 files changed

+65
-36
lines changed

2 files changed

+65
-36
lines changed

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
private import python
77
private import experimental.dataflow.DataFlow
88
private import experimental.dataflow.RemoteFlowSources
9+
private import experimental.dataflow.TaintTracking
910
private import experimental.semmle.python.Concepts
10-
import semmle.python.regex
11+
private import semmle.python.regex
1112

1213
/**
1314
* Provides models for the `django` PyPI package.
@@ -455,4 +456,32 @@ private module Django {
455456
override string getSourceType() { result = "django.http.request.HttpRequest" }
456457
}
457458

459+
private class DjangoHttpRequstAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
460+
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
461+
nodeFrom = django::http::request::HttpRequest::instance() and
462+
exists(DataFlow::AttrRead read | nodeTo = read and read.getObject() = nodeFrom |
463+
read.getAttributeName() in ["body",
464+
// str / bytes
465+
"path", "path_info", "method", "encoding", "content_type",
466+
// django.http.QueryDict
467+
// TODO: Model QueryDict
468+
"GET", "POST",
469+
// dict[str, str]
470+
"content_params", "COOKIES",
471+
// dict[str, Any]
472+
"META",
473+
// HttpHeaders (case insensitive dict-like)
474+
"headers",
475+
// MultiValueDict[str, UploadedFile]
476+
// TODO: Model MultiValueDict
477+
// TODO: Model UploadedFile
478+
"FILES",
479+
// django.urls.ResolverMatch
480+
// TODO: Model ResolverMatch
481+
"resolver_match"]
482+
// TODO: Handle calls to methods
483+
// TODO: Handle that a HttpRequest is iterable
484+
)
485+
}
486+
}
458487
}

python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,56 @@
22
| taint_test.py:7 | ok | test_taint | foo |
33
| taint_test.py:8 | ok | test_taint | baz |
44
| taint_test.py:14 | ok | test_taint | request |
5-
| taint_test.py:16 | fail | test_taint | request.body |
6-
| taint_test.py:17 | fail | test_taint | request.path |
7-
| taint_test.py:18 | fail | test_taint | request.path_info |
8-
| taint_test.py:22 | fail | test_taint | request.method |
9-
| taint_test.py:24 | fail | test_taint | request.encoding |
10-
| taint_test.py:25 | fail | test_taint | request.content_type |
11-
| taint_test.py:28 | fail | test_taint | request.content_params |
12-
| taint_test.py:29 | fail | test_taint | request.content_params["key"] |
13-
| taint_test.py:30 | fail | test_taint | request.content_params.get(..) |
14-
| taint_test.py:34 | fail | test_taint | request.GET |
15-
| taint_test.py:35 | fail | test_taint | request.GET["key"] |
16-
| taint_test.py:36 | fail | test_taint | request.GET.get(..) |
5+
| taint_test.py:16 | ok | test_taint | request.body |
6+
| taint_test.py:17 | ok | test_taint | request.path |
7+
| taint_test.py:18 | ok | test_taint | request.path_info |
8+
| taint_test.py:22 | ok | test_taint | request.method |
9+
| taint_test.py:24 | ok | test_taint | request.encoding |
10+
| taint_test.py:25 | ok | test_taint | request.content_type |
11+
| taint_test.py:28 | ok | test_taint | request.content_params |
12+
| taint_test.py:29 | ok | test_taint | request.content_params["key"] |
13+
| taint_test.py:30 | ok | test_taint | request.content_params.get(..) |
14+
| taint_test.py:34 | ok | test_taint | request.GET |
15+
| taint_test.py:35 | ok | test_taint | request.GET["key"] |
16+
| taint_test.py:36 | ok | test_taint | request.GET.get(..) |
1717
| taint_test.py:37 | fail | test_taint | request.GET.getlist(..) |
1818
| taint_test.py:38 | fail | test_taint | request.GET.getlist(..)[0] |
19-
| taint_test.py:39 | fail | test_taint | request.GET.pop(..) |
20-
| taint_test.py:40 | fail | test_taint | request.GET.pop(..)[0] |
21-
| taint_test.py:41 | fail | test_taint | request.GET.popitem()[0] |
22-
| taint_test.py:42 | fail | test_taint | request.GET.popitem()[1] |
23-
| taint_test.py:43 | fail | test_taint | request.GET.popitem()[1][0] |
19+
| taint_test.py:39 | ok | test_taint | request.GET.pop(..) |
20+
| taint_test.py:40 | ok | test_taint | request.GET.pop(..)[0] |
21+
| taint_test.py:41 | ok | test_taint | request.GET.popitem()[0] |
22+
| taint_test.py:42 | ok | test_taint | request.GET.popitem()[1] |
23+
| taint_test.py:43 | ok | test_taint | request.GET.popitem()[1][0] |
2424
| taint_test.py:44 | fail | test_taint | request.GET.dict() |
2525
| taint_test.py:45 | fail | test_taint | request.GET.dict()["key"] |
2626
| taint_test.py:46 | fail | test_taint | request.GET.urlencode() |
27-
| taint_test.py:49 | fail | test_taint | request.POST |
28-
| taint_test.py:52 | fail | test_taint | request.COOKIES |
29-
| taint_test.py:53 | fail | test_taint | request.COOKIES["key"] |
30-
| taint_test.py:54 | fail | test_taint | request.COOKIES.get(..) |
31-
| taint_test.py:57 | fail | test_taint | request.FILES |
32-
| taint_test.py:58 | fail | test_taint | request.FILES["key"] |
27+
| taint_test.py:49 | ok | test_taint | request.POST |
28+
| taint_test.py:52 | ok | test_taint | request.COOKIES |
29+
| taint_test.py:53 | ok | test_taint | request.COOKIES["key"] |
30+
| taint_test.py:54 | ok | test_taint | request.COOKIES.get(..) |
31+
| taint_test.py:57 | ok | test_taint | request.FILES |
32+
| taint_test.py:58 | ok | test_taint | request.FILES["key"] |
3333
| taint_test.py:59 | fail | test_taint | request.FILES["key"].content_type |
3434
| taint_test.py:60 | fail | test_taint | request.FILES["key"].content_type_extra |
3535
| taint_test.py:61 | fail | test_taint | request.FILES["key"].content_type_extra["key"] |
3636
| taint_test.py:62 | fail | test_taint | request.FILES["key"].charset |
3737
| taint_test.py:63 | fail | test_taint | request.FILES["key"].name |
3838
| taint_test.py:64 | fail | test_taint | request.FILES["key"].file |
3939
| taint_test.py:65 | fail | test_taint | request.FILES["key"].file.read() |
40-
| taint_test.py:67 | fail | test_taint | request.FILES.get(..) |
40+
| taint_test.py:67 | ok | test_taint | request.FILES.get(..) |
4141
| taint_test.py:68 | fail | test_taint | request.FILES.get(..).name |
4242
| taint_test.py:69 | fail | test_taint | request.FILES.getlist(..) |
4343
| taint_test.py:70 | fail | test_taint | request.FILES.getlist(..)[0] |
4444
| taint_test.py:71 | fail | test_taint | request.FILES.getlist(..)[0].name |
4545
| taint_test.py:72 | fail | test_taint | request.FILES.dict() |
4646
| taint_test.py:73 | fail | test_taint | request.FILES.dict()["key"] |
4747
| taint_test.py:74 | fail | test_taint | request.FILES.dict()["key"].name |
48-
| taint_test.py:77 | fail | test_taint | request.META |
49-
| taint_test.py:78 | fail | test_taint | request.META["HTTP_USER_AGENT"] |
50-
| taint_test.py:79 | fail | test_taint | request.META.get(..) |
51-
| taint_test.py:82 | fail | test_taint | request.headers |
52-
| taint_test.py:83 | fail | test_taint | request.headers["user-agent"] |
53-
| taint_test.py:84 | fail | test_taint | request.headers["USER_AGENT"] |
54-
| taint_test.py:87 | fail | test_taint | request.resolver_match |
48+
| taint_test.py:77 | ok | test_taint | request.META |
49+
| taint_test.py:78 | ok | test_taint | request.META["HTTP_USER_AGENT"] |
50+
| taint_test.py:79 | ok | test_taint | request.META.get(..) |
51+
| taint_test.py:82 | ok | test_taint | request.headers |
52+
| taint_test.py:83 | ok | test_taint | request.headers["user-agent"] |
53+
| taint_test.py:84 | ok | test_taint | request.headers["USER_AGENT"] |
54+
| taint_test.py:87 | ok | test_taint | request.resolver_match |
5555
| taint_test.py:88 | fail | test_taint | request.resolver_match.args |
5656
| taint_test.py:89 | fail | test_taint | request.resolver_match.args[0] |
5757
| taint_test.py:90 | fail | test_taint | request.resolver_match.kwargs |
@@ -63,10 +63,10 @@
6363
| taint_test.py:100 | fail | test_taint | request.readlines() |
6464
| taint_test.py:101 | fail | test_taint | request.readlines()[0] |
6565
| taint_test.py:102 | fail | test_taint | ListComp |
66-
| taint_test.py:108 | fail | test_taint | args |
67-
| taint_test.py:109 | fail | test_taint | args[0] |
68-
| taint_test.py:110 | fail | test_taint | kwargs |
69-
| taint_test.py:111 | fail | test_taint | kwargs["key"] |
66+
| taint_test.py:108 | ok | test_taint | args |
67+
| taint_test.py:109 | ok | test_taint | args[0] |
68+
| taint_test.py:110 | ok | test_taint | kwargs |
69+
| taint_test.py:111 | ok | test_taint | kwargs["key"] |
7070
| taint_test.py:115 | ok | test_taint | request.current_app |
7171
| taint_test.py:120 | ok | test_taint | request.get_host() |
7272
| taint_test.py:121 | ok | test_taint | request.get_port() |

0 commit comments

Comments
 (0)