######################################## How to use a Content Security Policy ######################################## A Content Security Policy (CSP) tells the browser which scripts and stylesheets it is allowed to run. The strictest practical policy is a *nonce-based* one: the server generates a random token for every response, puts it in the ``Content-Security-Policy`` header, and repeats it on every asset it trusts. Anything without the token -- including markup injected by an attacker -- is refused. django CMS renders the nonce on all assets it emits itself, so the admin, the page tree, the toolbar and the wizards keep working under such a policy. .. versionadded:: 5.1 Nonce support requires Django 6.1 or later. On Django 5.2 and 6.0 the templates render exactly as before, without a ``nonce`` attribute. ****** Set-up ****** Django 6.1 ships CSP support out of the box. Three pieces are needed: #. Add the middleware that generates the nonce and writes the header:: MIDDLEWARE = [ "django.middleware.csp.ContentSecurityPolicyMiddleware", ... ] #. Add the context processor that makes the nonce available to templates:: TEMPLATES = [ { ... "OPTIONS": { "context_processors": [ ... "django.template.context_processors.csp", ], }, }, ] #. Declare a policy that uses the nonce placeholder:: from django.utils.csp import CSP SECURE_CSP = { "default-src": [CSP.SELF], "script-src": [CSP.SELF, CSP.NONCE], "style-src": [CSP.SELF, CSP.NONCE], } ``CSP.NONCE`` is replaced with the request's nonce when the header is built. See `Django's CSP how-to `_ for the full picture. .. note:: Start with ``SECURE_CSP_REPORT_ONLY`` instead of ``SECURE_CSP``. The browser then reports violations without blocking anything, which lets you find assets from your own templates or from third-party apps that do not carry the nonce yet. ******************************* Nonces in your own templates ******************************* Any script or stylesheet **you** add has to carry the nonce as well. Django 6.1 registers a built-in ``{% csp_nonce_attr %}`` tag for that, but it does not exist on Django 5.2 and 6.0. If your project or add-on supports those versions too, load django CMS' cross-version version of the tag instead: .. code-block:: html+django {% load cms_static %} The tag renders ``nonce="..."`` when a nonce is available and nothing at all otherwise, so a single template works on every supported Django version. Form and widget media take the nonce as an argument: .. code-block:: html+django {% csp_nonce_attr form.media %} If you need the assets one at a time -- for example to wrap each of them in a separate sekizai ``{% addtoblock %}``, the way the toolbar does -- use ``{% render_media_assets %}``: .. code-block:: html+django {% render_media_assets form.media "css" as css_assets %} {% for css in css_assets %} {% addtoblock "css" %}{{ css }}{% endaddtoblock %} {% endfor %} The second argument is either ``"css"`` or ``"js"``. ********************************** What does *not* need a nonce ********************************** ``