File: csp.txt

package info (click to toggle)
python-django 3%3A6.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 62,104 kB
  • sloc: python: 371,210; javascript: 19,376; xml: 211; makefile: 187; sh: 28
file content (297 lines) | stat: -rw-r--r-- 11,701 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
=======================
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`.

Decorators
==========

.. module:: django.views.decorators.csp

Django provides decorators to control the Content Security Policy headers on a
per-view basis. These allow overriding or disabling the enforced or report-only
policy for specific views, providing fine-grained control when the global
settings are not sufficient. Applying these overrides fully replaces the base
CSP: they do not merge with existing rules. They can be used alongside the
constants defined in :class:`~django.utils.csp.CSP`.

.. warning::

    Weakening or disabling a CSP policy on any page can compromise the security
    of the entire site. Because of the "same origin" policy, an attacker could
    exploit a vulnerability on one page to access other parts of the site.

.. function:: csp_override(config)(view)

   Overrides the ``Content-Security-Policy`` header for the decorated view
   using directives in the same format as the :setting:`SECURE_CSP` setting.

   The ``config`` argument must be a mapping with the desired CSP directives.
   If ``config`` is an empty mapping (``{}``), no CSP enforcement header will
   be added to the response returned by that view, effectively disabling CSP
   for that view.

   Examples::

       from django.http import HttpResponse
       from django.utils.csp import CSP
       from django.views.decorators.csp import csp_override


       @csp_override(
           {
               "default-src": [CSP.SELF],
               "img-src": [CSP.SELF, "data:"],
           }
       )
       def my_view(request):
           return HttpResponse("Custom Content-Security-Policy header applied")


       @csp_override({})
       def my_other_view(request):
           return HttpResponse("No Content-Security-Policy header added")


.. function:: csp_report_only_override(config)(view)

   Overrides the ``Content-Security-Policy-Report-Only`` header for the
   decorated view using directives in the same format as the
   :setting:`SECURE_CSP_REPORT_ONLY` setting.

   Like :func:`csp_override`, the ``config`` argument must be a mapping with
   the desired CSP directives. If ``config`` is an empty mapping (``{}``), no
   CSP report-only header will be added to the response returned by that view,
   effectively disabling report-only CSP for that view.

   Examples::

       from django.http import HttpResponse
       from django.utils.csp import CSP
       from django.views.decorators.csp import csp_report_only_override


       @csp_report_only_override(
           {
               "default-src": [CSP.SELF],
               "img-src": [CSP.SELF, "data:"],
               "report-uri": "https://mysite.com/csp-report/",
           }
       )
       def my_view(request):
           return HttpResponse("Custom Content-Security-Policy-Report-Only header applied")


       @csp_report_only_override({})
       def my_other_view(request):
           return HttpResponse("No Content-Security-Policy-Report-Only header added")

The examples above assume function-based views. For class-based views, see the
:ref:`guide for decorating class-based views <decorating-class-based-views>`.

.. _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.