Skip to content

Commit b80288a

Browse files
committed
[5.1.x] Added security reporting guidelines.
Backport of 5935336 from main.
1 parent ce8dd44 commit b80288a

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

docs/internals/security.txt

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,131 @@ the industry-standard 90 days. Confirmed vulnerabilities with a
4343

4444
.. _our public Trac instance: https://code.djangoproject.com/query
4545

46+
Reporting guidelines
47+
--------------------
48+
49+
Include a runnable proof of concept
50+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
51+
52+
Please privately share a minimal Django project or code snippet that
53+
demonstrates the potential vulnerability. Include clear instructions on how to
54+
set up, run, and reproduce the issue.
55+
56+
Please do not attach screenshots of code.
57+
58+
User input must be sanitized
59+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
60+
61+
Reports based on a failure to sanitize user input are not valid security
62+
vulnerabilities. It is the developer's responsibility to properly handle user
63+
input. This principle is explained in our :ref:`security documentation
64+
<sanitize-user-input>`.
65+
66+
For example, the following is **not considered valid** because ``email`` has
67+
not been sanitized::
68+
69+
from django.core.mail import send_mail
70+
from django.http import JsonResponse
71+
72+
73+
def my_proof_of_concept(request):
74+
email = request.GET.get("email", "")
75+
send_mail("Email subject", "Email body", email, ["[email protected]"])
76+
return JsonResponse(status=200)
77+
78+
Developers must **always validate and sanitize input** before using it. The
79+
correct approach would be to use a Django form to ensure ``email`` is properly
80+
validated::
81+
82+
from django import forms
83+
from django.core.mail import send_mail
84+
from django.http import JsonResponse
85+
86+
87+
class EmailForm(forms.Form):
88+
email = forms.EmailField()
89+
90+
91+
def my_proof_of_concept(request):
92+
form = EmailForm(request.GET)
93+
if form.is_valid():
94+
send_mail(
95+
"Email subject",
96+
"Email body",
97+
form.cleaned_data["email"],
98+
99+
)
100+
return JsonResponse(status=200)
101+
return JsonResponse(form.errors, status=400)
102+
103+
Similarly, as Django's raw SQL constructs (such as :meth:`~.QuerySet.extra` and
104+
:class:`.RawSQL` expression) provide developers with full control over the
105+
query, they are insecure if user input is not properly handled. As explained in
106+
our :ref:`security documentation <sql-injection-protection>`, it is the
107+
developer's responsibility to safely process user input for these functions.
108+
109+
For instance, the following is **not considered valid** because ``query`` has
110+
not been sanitized::
111+
112+
from django.shortcuts import HttpResponse
113+
from .models import MyModel
114+
115+
116+
def my_proof_of_concept(request):
117+
query = request.GET.get("query", "")
118+
q = MyModel.objects.extra(select={"id": query})
119+
return HttpResponse(q.values())
120+
121+
Request headers and URLs must be under 8K bytes
122+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123+
124+
To prevent denial-of-service (DoS) attacks, production-grade servers impose
125+
limits on request header and URL sizes. For example, by default Gunicorn allows
126+
up to roughly:
127+
128+
* `4k bytes for a URL`_
129+
* `8K bytes for a request header`_
130+
131+
Other web servers, such as Nginx and Apache, have similar restrictions to
132+
prevent excessive resource consumption.
133+
134+
Consequently, the Django security team will not consider reports that rely on
135+
request headers or URLs exceeding 8K bytes, as such inputs are already
136+
mitigated at the server level in production environments.
137+
138+
.. admonition:: :djadmin:`runserver` should never be used in production
139+
140+
Django's built-in development server does not enforce these limits because
141+
it is not designed to be a production server.
142+
143+
.. _`4k bytes for a URL`: https://docs.gunicorn.org/en/stable/settings.html#limit-request-line
144+
.. _`8k bytes for a request header`: https://docs.gunicorn.org/en/stable/settings.html#limit-request-field-size
145+
146+
The request body must be under 2.5 MB
147+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148+
149+
The :setting:`DATA_UPLOAD_MAX_MEMORY_SIZE` setting limits the default maximum
150+
request body size to 2.5 MB.
151+
152+
As this is enforced on all production-grade Django projects by default, a proof
153+
of concept must not exceed 2.5 MB in the request body to be considered valid.
154+
155+
Issues resulting from large, but potentially reasonable setting values, should
156+
be reported using the `public ticket tracker`_ for hardening.
157+
158+
.. _public ticket tracker: https://code.djangoproject.com/
159+
160+
Code under test must feasibly exist in a Django project
161+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
162+
163+
The proof of concept must plausibly occur in a production-grade Django
164+
application, reflecting real-world scenarios and following standard development
165+
practices.
166+
167+
Django contains many private and undocumented functions that are not part of
168+
its public API. If a vulnerability depends on directly calling these internal
169+
functions in an unsafe way, it will not be considered a valid security issue.
170+
46171
.. _security-report-evaluation:
47172

48173
How does Django evaluate a report

docs/topics/security.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ Security in Django
55
This document is an overview of Django's security features. It includes advice
66
on securing a Django-powered site.
77

8+
.. _sanitize-user-input:
9+
10+
Always sanitize user input
11+
==========================
12+
13+
The golden rule of web application security is to never trust user-controlled
14+
data. Hence, all user input should be sanitized before being used in your
15+
application. See the :doc:`forms documentation </topics/forms/index>` for
16+
details on validating user inputs in Django.
17+
818
.. _cross-site-scripting:
919

1020
Cross site scripting (XSS) protection

0 commit comments

Comments
 (0)