Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 179 additions & 13 deletions docs/internals/security.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@ implications, please send a description of the issue via email to
team <https://www.djangoproject.com/foundation/teams/#security-team>`_.

Once you've submitted an issue via email, you should receive an acknowledgment
from a member of the security team within 48 hours, and depending on the
action to be taken, you may receive further followup emails.
from a member of the security team within 3 working days. After that, the
security team will begin their analysis. Depending on the action to be taken,
you may receive followup emails. It can take several weeks before the security
team comes to a conclusion. There is no need to chase the security team unless
you discover new, relevant information. All reports aim to be resolved within
the industry-standard 90 days. Confirmed vulnerabilities with a
:ref:`high severity level <severity-levels>` will be addressed promptly.

.. admonition:: Sending encrypted reports

Expand All @@ -38,6 +43,157 @@ action to be taken, you may receive further followup emails.

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

Reporting guidelines
--------------------

Include a runnable proof of concept
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Please privately share a minimal Django project or code snippet that
demonstrates the potential vulnerability. Include clear instructions on how to
set up, run, and reproduce the issue.

Please do not attach screenshots of code.

User input must be sanitized
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Reports based on a failure to sanitize user input are not valid security
vulnerabilities. It is the developer's responsibility to properly handle user
input. This principle is explained in our :ref:`security documentation
<sanitize-user-input>`.

For example, the following is **not considered valid** because ``email`` has
not been sanitized::

from django.core.mail import send_mail
from django.http import JsonResponse


def my_proof_of_concept(request):
email = request.GET.get("email", "")
send_mail("Email subject", "Email body", email, ["admin@example.com"])
return JsonResponse(status=200)

Developers must **always validate and sanitize input** before using it. The
correct approach would be to use a Django form to ensure ``email`` is properly
validated::

from django import forms
from django.core.mail import send_mail
from django.http import JsonResponse


class EmailForm(forms.Form):
email = forms.EmailField()


def my_proof_of_concept(request):
form = EmailForm(request.GET)
if form.is_valid():
send_mail(
"Email subject",
"Email body",
form.cleaned_data["email"],
["admin@example.com"],
)
return JsonResponse(status=200)
return JsonResponse(form.errors, status=400)

Similarly, as Django's raw SQL constructs (such as :meth:`~.QuerySet.extra` and
:class:`.RawSQL` expression) provide developers with full control over the
query, they are insecure if user input is not properly handled. As explained in
our :ref:`security documentation <sql-injection-protection>`, it is the
developer's responsibility to safely process user input for these functions.

For instance, the following is **not considered valid** because ``query`` has
not been sanitized::

from django.shortcuts import HttpResponse
from .models import MyModel


def my_proof_of_concept(request):
query = request.GET.get("query", "")
q = MyModel.objects.extra(select={"id": query})
return HttpResponse(q.values())

Request headers and URLs must be under 8K bytes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To prevent denial-of-service (DoS) attacks, production-grade servers impose
limits on request header and URL sizes. For example, by default Gunicorn allows
up to roughly:

* `4k bytes for a URL`_
* `8K bytes for a request header`_

Other web servers, such as Nginx and Apache, have similar restrictions to
prevent excessive resource consumption.

Consequently, the Django security team will not consider reports that rely on
request headers or URLs exceeding 8K bytes, as such inputs are already
mitigated at the server level in production environments.

.. admonition:: :djadmin:`runserver` should never be used in production

Django's built-in development server does not enforce these limits because
it is not designed to be a production server.

.. _`4k bytes for a URL`: https://docs.gunicorn.org/en/stable/settings.html#limit-request-line
.. _`8k bytes for a request header`: https://docs.gunicorn.org/en/stable/settings.html#limit-request-field-size

The request body must be under 2.5 MB
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The :setting:`DATA_UPLOAD_MAX_MEMORY_SIZE` setting limits the default maximum
request body size to 2.5 MB.

As this is enforced on all production-grade Django projects by default, a proof
of concept must not exceed 2.5 MB in the request body to be considered valid.

Issues resulting from large, but potentially reasonable setting values, should
be reported using the `public ticket tracker`_ for hardening.

.. _public ticket tracker: https://code.djangoproject.com/

Code under test must feasibly exist in a Django project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The proof of concept must plausibly occur in a production-grade Django
application, reflecting real-world scenarios and following standard development
practices.

Django contains many private and undocumented functions that are not part of
its public API. If a vulnerability depends on directly calling these internal
functions in an unsafe way, it will not be considered a valid security issue.

Content displayed by the Django Template Language must be under 100 KB
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Django Template Language (DTL) is designed for building the content needed
to display web pages. In particular its text filters are meant for that kind of
usage.

For reference, the complete works of Shakespeare have about 3.5 million bytes
in plain-text ASCII encoding. Displaying such in a single request is beyond the
scope of almost all websites, and so outside the scope of the DTL too.

Text processing is expensive. Django makes no guarantee that DTL text filters
are never subject to degraded performance if passed deliberately crafted,
sufficiently large inputs. Under default configurations, Django makes it
difficult for sites to accidentally accept such payloads from untrusted
sources, but, if it is necessary to display large amounts of user-provided
content, it’s important that basic security measures are taken.

User-provided content should always be constrained to known maximum length. It
should be filtered to remove malicious content, and validated to match expected
formats. It should then be processed offline, if necessary, before being
displayed.

Proof of concepts which use over 100 KB of data to be processed by the DTL will
be considered invalid.

.. _security-report-evaluation:

How does Django evaluate a report
Expand Down Expand Up @@ -110,20 +266,15 @@ will not issue patches or new releases for those versions.

.. _main development branch: https://github.com/django/django/

.. _security-disclosure:
.. _severity-levels:

How Django discloses security issues
====================================
Security issue severity levels
==============================

Our process for taking a security issue from private discussion to
public disclosure involves multiple steps.
The severity level of a security vulnerability is determined by the attack
type.

Approximately one week before public disclosure, we send two notifications:

First, we notify |django-announce| of the date and approximate time of the
upcoming security release, as well as the severity of the issues. This is to
aid organizations that need to ensure they have staff available to handle
triaging our announcement and upgrade Django as needed. Severity levels are:
Severity levels are:

* **High**

Expand All @@ -144,6 +295,21 @@ triaging our announcement and upgrade Django as needed. Severity levels are:
* Unvalidated redirects/forwards
* Issues requiring an uncommon configuration option

.. _security-disclosure:

How Django discloses security issues
====================================

Our process for taking a security issue from private discussion to
public disclosure involves multiple steps.

Approximately one week before public disclosure, we send two notifications:

First, we notify |django-announce| of the date and approximate time of the
upcoming security release, as well as the severity of the issues. This is to
aid organizations that need to ensure they have staff available to handle
triaging our announcement and upgrade Django as needed.

Second, we notify a list of :ref:`people and organizations
<security-notifications>`, primarily composed of operating-system vendors and
other distributors of Django. This email is signed with the PGP key of someone
Expand Down
11 changes: 0 additions & 11 deletions docs/ref/templates/builtins.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2920,17 +2920,6 @@ Django's built-in :tfilter:`escape` filter. The default value for
email addresses that contain single quotes (``'``), things won't work as
expected. Apply this filter only to plain text.

.. warning::

Using ``urlize`` or ``urlizetrunc`` can incur a performance penalty, which
can become severe when applied to user controlled values such as content
stored in a :class:`~django.db.models.TextField`. You can use
:tfilter:`truncatechars` to add a limit to such inputs:

.. code-block:: html+django

{{ value|truncatechars:500|urlize }}

.. templatefilter:: urlizetrunc

``urlizetrunc``
Expand Down
10 changes: 10 additions & 0 deletions docs/topics/security.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ Security in Django
This document is an overview of Django's security features. It includes advice
on securing a Django-powered site.

.. _sanitize-user-input:

Always sanitize user input
==========================

The golden rule of web application security is to never trust user-controlled
data. Hence, all user input should be sanitized before being used in your
application. See the :doc:`forms documentation </topics/forms/index>` for
details on validating user inputs in Django.

.. _cross-site-scripting:

Cross site scripting (XSS) protection
Expand Down