Content Security Policy for Django 6
Content Security Policy is a security feature that allows you to control which sources resources can be loaded from. That includes scripts, styles, fonts, and many others.
How does it work? You include a specific header, either Content-Security-Policy or Content-Security-Policy-Report-Only (for reports only), and specify a set of directives. You can learn more about what these directives are in this article on the safest Content Security Policy.
In this article, we'll see how to set this up with Django.
Including CSP middleware
The Content Security Policy middleware was introduced in Django 6 and is responsible for inserting headers, overriding them, and generating nonces (more on that later) when required.
Add the header to your MIDDLEWARE in settings:
MIDDLEWARE = [
# ...
"django.middleware.csp.ContentSecurityPolicyMiddleware",
# ...
]
In settings.py:
from django.utils.csp import CSP
# To enforce a CSP policy:
SECURE_CSP = {
# a fallback for any directive that isn't set
# self means same origin as the page itself
"default-src": [CSP.SELF],
# Where scripts can be loaded from.
"script-src": [CSP.SELF],
# Where stylesheets can be loaded from.
"style-src": [CSP.SELF],
# Where images can be loaded from (also allows inline `data:` URIs).
"img-src": [CSP.SELF, "data:"],
# Where fonts can be loaded from.
"font-src": [CSP.SELF],
# URLs the page is allowed to connect to (fetch, XHR, WebSocket).
"connect-src": [CSP.SELF],
# Restricts <base> tag URLs to prevent base-tag injection attacks.
"base-uri": [CSP.SELF],
# Disallows embedding plugins like <object>, <embed>, <applet>.
"object-src": [CSP.NONE],
# Restricts where the page can be submitted via <form action>.
"form-action": [CSP.SELF],
# Disallows the page from being framed (clickjacking protection).
"frame-ancestors": [CSP.NONE],
}
# Or for report-only mode:
SECURE_CSP_REPORT_ONLY = {
# same directives as above
}
Note that we are using these constants from https://github.com/django/django/blob/stable/6.0.x/django/utils/csp.py, which are simply standard keywords defined in the CSP standard.
Using nonce
A nonce is a unique token that is generated for every request. When you include it in the header and also in the script itself, the browser can verify the validity of the script and thus know that it's safe to execute.
Django provides a way to opt into nonces by adding CSP.NONCE to a directive. On every request, Django will generate a fresh token and emit it in the header. Any <script> or <style> tag that carries the same nonce attribute will then be trusted by the browser.
from django.utils.csp import CSP
SECURE_CSP = {
"default-src": [CSP.SELF],
# Allow self-hosted scripts and script tags with matching `nonce` attr.
"script-src": [CSP.SELF, CSP.NONCE],
# Example of the less secure 'unsafe-inline' option.
"style-src": [CSP.SELF, CSP.UNSAFE_INLINE],
}
To expose the generated nonce to your templates, also register the csp context processor:
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"OPTIONS": {
"context_processors": [
# ...
"django.template.context_processors.csp",
],
},
},
]
You can now reference {{ csp_nonce }} in your templates whenever you need to mark an inline <script> or <style> tag as trusted:
<script nonce="{{ csp_nonce }}">
console.log("This inline script is allowed by CSP.");
</script>
Custom CSP headers in controllers
Django also allows you to override the CSP header on a per-view basis. You can use the @csp_override decorator for that:
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 some_view(request):
return HttpResponse("Custom Content-Security-Policy header applied")
Where to go next?
Let me also include some resources for further reading:
To learn more on how CSP works, refer to the MDN guide.
For the official Django documentation on CSP, see this page.
Construct a policy that suits you with our free builder.
To test an existing policy, try our free CSP validator.
Set up a reporting endpoint and get organized reports about any CSP violations on your site.