Built-in CSP Support in Django 6.0
Django 6.0 adds native Content Security Policy (CSP) header support. No need to install django-csp anymore: configuration is done directly in settings.py and a middleware automatically handles headers and nonces for inline scripts.
Configuration
Enable the CSP middleware and configure the directives in settings.py. Django automatically generates a unique nonce per request to authorize trusted inline scripts.
python
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.middleware.csp.CSPMiddleware', # new
...
]
CONTENT_SECURITY_POLICY = {
'default-src': ["'self'"],
'script-src': ["'self'", "'nonce'"], # auto-managed nonce
'style-src': ["'self'", "https://fonts.googleapis.com"],
'img-src': ["'self'", "data:"],
'font-src': ["'self'", "https://fonts.gstatic.com"],
'connect-src': ["'self'"],
}
# Report-only mode for testing without blocking:
CONTENT_SECURITY_POLICY_REPORT_ONLY = True
CONTENT_SECURITY_POLICY_REPORT_URI = '/csp-report/'
Inline Scripts with Nonce
In templates, the {% csp_nonce %} tag inserts the request's unique nonce. Only scripts carrying this nonce are allowed to execute.
htmldjango
{# templates/base.html #}
{% load csp %}
<!DOCTYPE html>
<html>
<head>
<title>My Secure Site</title>
{# Inline script authorized by nonce #}
<script nonce="{% csp_nonce %}">
console.log('This script is allowed by CSP');
</script>
</head>
<body>
{# A script without a nonce will be blocked by the browser #}
{{ content }}
</body>
</html>
{# Automatically generated HTTP header:
Content-Security-Policy: default-src 'self';
script-src 'self' 'nonce-abc123def456'; ... #}
