Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 08af839

Browse files
Rasmus Lerchedahl PetersenRasmus Lerchedahl Petersen
authored andcommitted
Python: django.http.response.HttpResponseRedirect
1 parent 52be896 commit 08af839

2 files changed

Lines changed: 76 additions & 6 deletions

File tree

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

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,13 @@ private module Django {
499499
* WARNING: Only holds for a few predefined attributes.
500500
*/
501501
private DataFlow::Node http_attr(DataFlow::TypeTracker t, string attr_name) {
502-
attr_name in ["request", "HttpRequest", "response", "HttpResponse", "JsonResponse"] and
502+
attr_name in ["request",
503+
// request
504+
"HttpRequest",
505+
// response
506+
"response", "HttpResponse",
507+
// HttpResponse subclasses
508+
"HttpResponseRedirect", "JsonResponse"] and
503509
(
504510
t.start() and
505511
result = DataFlow::importNode("django.http" + "." + attr_name)
@@ -641,7 +647,7 @@ private module Django {
641647
* WARNING: Only holds for a few predefined attributes.
642648
*/
643649
private DataFlow::Node response_attr(DataFlow::TypeTracker t, string attr_name) {
644-
attr_name in ["HttpResponse", "JsonResponse"] and
650+
attr_name in ["HttpResponse", "HttpResponseRedirect", "JsonResponse"] and
645651
(
646652
t.start() and
647653
result = DataFlow::importNode("django.http.response" + "." + attr_name)
@@ -742,7 +748,70 @@ private module Django {
742748

743749
// ---------------------------------------------------------------------------
744750
// HttpResponse subclasses
751+
// see https://docs.djangoproject.com/en/3.1/ref/request-response/#httpresponse-subclasses
745752
// ---------------------------------------------------------------------------
753+
/**
754+
* Provides models for the `django.http.response.HttpResponseRedirect` class
755+
*
756+
* See https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.HttpResponseRedirect.
757+
*/
758+
module HttpResponseRedirect {
759+
/** Gets a reference to the `django.http.response.HttpResponseRedirect` class. */
760+
private DataFlow::Node classRef(DataFlow::TypeTracker t) {
761+
t.start() and
762+
result = response_attr("HttpResponseRedirect")
763+
or
764+
// TODO: remove/expand this part of the template as needed
765+
// Handle `http.HttpResponseRedirect` alias
766+
t.start() and
767+
result = http_attr("HttpResponseRedirect")
768+
or
769+
exists(DataFlow::TypeTracker t2 | result = classRef(t2).track(t2, t))
770+
}
771+
772+
/** Gets a reference to the `django.http.response.HttpResponseRedirect` class. */
773+
DataFlow::Node classRef() { result = classRef(DataFlow::TypeTracker::end()) }
774+
775+
/**
776+
* A source of an instance of `django.http.response.HttpResponseRedirect`.
777+
*
778+
* This can include instantiation of the class, return value from function
779+
* calls, or a special parameter that will be set when functions are call by external
780+
* library.
781+
*
782+
* Use `HttpResponseRedirect::instance()` predicate to get references to instances of `django.http.response.HttpResponseRedirect`.
783+
*/
784+
abstract class InstanceSource extends HTTP::Server::HttpResponse::Range, DataFlow::Node {
785+
}
786+
787+
/** A direct instantiation of `django.http.response.HttpResponseRedirect`. */
788+
private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode {
789+
override CallNode node;
790+
791+
ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }
792+
793+
override DataFlow::Node getBody() {
794+
result.asCfgNode() in [node.getArg(0), node.getArgByName("content")]
795+
}
796+
797+
// How to support the `headers` argument here?
798+
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
799+
800+
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
801+
}
802+
803+
/** Gets a reference to an instance of `django.http.response.HttpResponseRedirect`. */
804+
private DataFlow::Node instance(DataFlow::TypeTracker t) {
805+
t.start() and
806+
result instanceof InstanceSource
807+
or
808+
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
809+
}
810+
811+
/** Gets a reference to an instance of `django.http.response.HttpResponseRedirect`. */
812+
DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) }
813+
}
814+
746815
/**
747816
* Provides models for the `django.http.response.JsonResponse` class
748817
*

python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ def safe__manual_content_type(request):
1616
return HttpResponse('<img src="0" onerror="alert(1)">', content_type="text/plain") # $HttpResponse $mimetype=text/plain $responseBody='<img src="0" onerror="alert(1)">'
1717

1818
# XSS FP reported in https://github.com/github/codeql/issues/3466
19-
# Note: This should be a open-redirect sink, but not a XSS sink.
19+
# Note: This should be an open-redirect sink, but not an XSS sink.
2020
def or__redirect(request):
21-
return HttpResponseRedirect(request.GET.get("next")) # f-:HttpResponse
21+
return HttpResponseRedirect(request.GET.get("next")) # $HttpResponse $mimetype=text/html; charset=utf-8 $responseBody=Attribute()
22+
2223
# Ensure that simple subclasses are still vuln to XSS
2324
def xss__not_found(request):
24-
return HttpResponseNotFound(request.GET.get("name")) # f-:HttpResponse
25+
return HttpResponseNotFound(request.GET.get("name")) # $f-:HttpResponse
2526

26-
# Ensure we still have a XSS sink when manually setting the content_type to HTML
27+
# Ensure we still have an XSS sink when manually setting the content_type to HTML
2728
def xss__manual_response_type(request):
2829
return HttpResponse(request.GET.get("name"), content_type="text/html; charset=utf-8") # $HttpResponse $mimetype=text/html $responseBody=Attribute()

0 commit comments

Comments
 (0)