mirror of
https://github.com/django/django.git
synced 2025-08-23 18:29:12 +00:00
This initial work adds a pair of settings to configure specific CSP directives for enforcing or reporting policy violations, a new `django.middleware.csp.ContentSecurityPolicyMiddleware` to apply the appropriate headers to responses, and a context processor to support CSP nonces in templates for safely inlining assets. Relevant documentation has been added for the 6.0 release notes, security overview, a new how-to page, and a dedicated reference section. Thanks to the multiple reviewers for their precise and valuable feedback. Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
211 lines
8.4 KiB
Plaintext
211 lines
8.4 KiB
Plaintext
=======================
|
|
Content Security Policy
|
|
=======================
|
|
|
|
.. versionadded:: 6.0
|
|
|
|
.. module:: django.middleware.csp
|
|
:synopsis: Middleware for Content Security Policy headers
|
|
|
|
Content Security Policy (CSP) is a web security standard that helps prevent
|
|
content injection attacks by restricting the sources from which content can be
|
|
loaded. It plays an important role in a comprehensive :ref:`security strategy
|
|
<security-csp>`.
|
|
|
|
For configuration instructions in a Django project, see the :ref:`Using CSP
|
|
<csp-config>` documentation. For an HTTP guide about CSP, see the `MDN Guide on
|
|
CSP <https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP>`_.
|
|
|
|
.. _csp-overview:
|
|
|
|
Overview
|
|
========
|
|
|
|
The `Content-Security-Policy specification <https://www.w3.org/TR/CSP3/>`_
|
|
defines two complementary headers:
|
|
|
|
* ``Content-Security-Policy``: Enforces the CSP policy, blocking content that
|
|
violates the defined directives.
|
|
* ``Content-Security-Policy-Report-Only``: Reports CSP violations without
|
|
blocking content, allowing for non-intrusive testing.
|
|
|
|
Each policy is composed of one or more directives and their values, which
|
|
together instruct the browser on how to handle specific types of content.
|
|
|
|
When the :class:`~django.middleware.csp.ContentSecurityPolicyMiddleware` is
|
|
enabled, Django automatically builds and attaches the appropriate headers to
|
|
each response based on the configured :ref:`settings <csp-settings>`, unless
|
|
they have already been set by another layer.
|
|
|
|
.. _csp-settings:
|
|
|
|
Settings
|
|
========
|
|
|
|
The :class:`~django.middleware.csp.ContentSecurityPolicyMiddleware` is
|
|
configured using the following settings:
|
|
|
|
* :setting:`SECURE_CSP`: defines the **enforced Content Security Policy**.
|
|
* :setting:`SECURE_CSP_REPORT_ONLY`: defines a **report-only Content Security Policy**.
|
|
|
|
.. admonition:: These settings can be used independently or together
|
|
|
|
* Use :setting:`SECURE_CSP` alone to enforce a policy that has already been
|
|
tested and verified.
|
|
* Use :setting:`SECURE_CSP_REPORT_ONLY` on its own to evaluate a new policy
|
|
without disrupting site behavior. This mode does not block violations, it
|
|
only logs them. It's useful for testing and monitoring, but provides no
|
|
protection against active threats.
|
|
* Use *both* to maintain an enforced baseline while experimenting with
|
|
changes. Even for well-established policies, continuing to collect reports
|
|
reports can help detect regressions, unexpected changes in behavior, or
|
|
potential tampering in production environments.
|
|
|
|
.. _csp-reports:
|
|
|
|
Policy violation reports
|
|
========================
|
|
|
|
When a CSP violation occurs, browsers typically log details to the developer
|
|
console, providing immediate feedback during development. To also receive these
|
|
reports programmatically, the policy must include a `reporting directive
|
|
<https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy#reporting_directives>`_
|
|
such as ``report-uri`` that specifies where violation data should be sent.
|
|
|
|
Django supports configuring these directives via the
|
|
:setting:`SECURE_CSP_REPORT_ONLY` settings, but reports will only be issued by
|
|
the browser if the policy explicitly includes a valid reporting directive.
|
|
|
|
Django does not provide built-in functionality to receive, store, or process
|
|
violation reports. To collect and analyze them, you must implement your own
|
|
reporting endpoint or integrate with a third-party monitoring service.
|
|
|
|
.. _csp-constants:
|
|
|
|
CSP constants
|
|
=============
|
|
|
|
Django provides predefined constants representing common CSP source expression
|
|
keywords such as ``'self'``, ``'none'``, and ``'unsafe-inline'``. These
|
|
constants are intended for use in the directive values defined in the settings.
|
|
|
|
They are available through the :class:`~django.utils.csp.CSP` enum, and using
|
|
them is recommended over raw strings. This helps avoid common mistakes such as
|
|
typos, improper quoting, or inconsistent formatting, and ensures compliance
|
|
with the CSP specification.
|
|
|
|
.. module:: django.utils.csp
|
|
:synopsis: Constants for Content Security Policy
|
|
|
|
.. class:: CSP
|
|
|
|
Enum providing standardized constants for common CSP source expressions.
|
|
|
|
.. attribute:: NONE
|
|
|
|
Represents ``'none'``. Blocks loading resources for the given directive.
|
|
|
|
.. attribute:: REPORT_SAMPLE
|
|
|
|
Represents ``'report-sample'``. Instructs the browser to include a sample
|
|
of the violating code in reports. Note that this may expose sensitive
|
|
data.
|
|
|
|
.. attribute:: SELF
|
|
|
|
Represents ``'self'``. Allows loading resources from the same origin
|
|
(same scheme, host, and port).
|
|
|
|
.. attribute:: STRICT_DYNAMIC
|
|
|
|
Represents ``'strict-dynamic'``. Allows execution of scripts loaded by a
|
|
trusted script (e.g., one with a valid nonce or hash), without needing
|
|
``'unsafe-inline'``.
|
|
|
|
.. attribute:: UNSAFE_EVAL
|
|
|
|
Represents ``'unsafe-eval'``. Allows use of ``eval()`` and similar
|
|
JavaScript functions. Strongly discouraged.
|
|
|
|
.. attribute:: UNSAFE_HASHES
|
|
|
|
Represents ``'unsafe-hashes'``. Allows inline event handlers and some
|
|
``javascript:`` URIs when their content hashes match a policy rule.
|
|
Requires CSP Level 3+.
|
|
|
|
.. attribute:: UNSAFE_INLINE
|
|
|
|
Represents ``'unsafe-inline'``. Allows execution of inline scripts,
|
|
styles, and ``javascript:`` URLs. Generally discouraged, especially for
|
|
scripts.
|
|
|
|
.. attribute:: WASM_UNSAFE_EVAL
|
|
|
|
Represents ``'wasm-unsafe-eval'``. Permits compilation and execution of
|
|
WebAssembly code without enabling ``'unsafe-eval'`` for scripts.
|
|
|
|
.. attribute:: NONCE
|
|
|
|
Django-specific placeholder value (``"<CSP_NONCE_SENTINEL>"``) used in
|
|
``script-src`` or ``style-src`` directives to activate nonce-based CSP.
|
|
This string is replaced at runtime by the
|
|
:class:`~django.middleware.csp.ContentSecurityPolicyMiddleware` with a
|
|
secure, random nonce that is generated for each request. See detailed
|
|
explanation in :ref:`csp-nonce`.
|
|
|
|
.. _csp-nonce:
|
|
|
|
Nonce usage
|
|
===========
|
|
|
|
A CSP nonce ("number used once") is a unique, random value generated per HTTP
|
|
response. Django supports nonces as a secure way to allow specific inline
|
|
``<script>`` or ``<style>`` elements to execute without relying on
|
|
``'unsafe-inline'``.
|
|
|
|
Nonces are enabled by including the special placeholder
|
|
:attr:`~django.utils.csp.CSP.NONCE` in the relevant directive(s) of your
|
|
:ref:`CSP settings <csp-settings>`, such as ``script-src`` or ``style-src``.
|
|
When present, the
|
|
:class:`~django.middleware.csp.ContentSecurityPolicyMiddleware`
|
|
will generate a nonce and insert the corresponding ``nonce-<value>`` source
|
|
expression into the CSP header.
|
|
|
|
To use this nonce in templates, the
|
|
:func:`~django.template.context_processors.csp` context processor needs to be
|
|
enabled. It adds a ``csp_nonce`` variable to the template context, allowing
|
|
inline elements to include a matching ``nonce={{ csp_nonce }}`` attribute in
|
|
inline scripts or styles.
|
|
|
|
The browser will only execute inline elements that include a ``nonce=<value>``
|
|
attribute matching the one specified in the ``Content-Security-Policy`` (or
|
|
``Content-Security-Policy-Report-Only``) header. This mechanism provides
|
|
fine-grained control over which inline code is allowed to run.
|
|
|
|
If a template includes ``{{ csp_nonce }}`` but the policy does not include
|
|
:attr:`~django.utils.csp.CSP.NONCE`, the HTML will include a nonce attribute,
|
|
but the header will lack the required source expression. In this case, the
|
|
browser will block the inline script or style (or report it for report-only
|
|
configurations).
|
|
|
|
Nonce generation and caching
|
|
----------------------------
|
|
|
|
Django's nonce generation is **lazy**: the middleware only generates a nonce if
|
|
``{{ csp_nonce }}`` is accessed during template rendering. This avoids
|
|
unnecessary work for pages that do not use nonces.
|
|
|
|
However, because nonces must be unique per request, extra care is needed when
|
|
using full-page caching (e.g., Django's cache middleware, CDN caching). Serving
|
|
cached responses with previously generated nonces may result in reuse across
|
|
users and requests. Although such responses may still appear to work (since the
|
|
nonce in the CSP header and HTML content match), reuse defeats the purpose of
|
|
the nonce and weakens security.
|
|
|
|
To ensure nonce-based policies remain effective:
|
|
|
|
* Avoid caching full responses that include ``{{ csp_nonce }}``.
|
|
* If caching is necessary, use a strategy that injects a fresh nonce on each
|
|
request, or consider refactoring your application to avoid inline scripts and
|
|
styles altogether.
|