Django cookbook · Intermediate
Harden security settings, including a Content Security Policy
The app passes development checks but ships without HTTPS enforcement, secure cookies or a CSP.
Approach
Enable HTTPS redirects and HSTS, secure cookies, and Django 6's built-in Content Security Policy middleware with
nonces for inline scripts. Verify with manage.py check --deploy.
Solution
# settings/production.py
from django.utils.csp import CSP
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") # only behind a proxy that sets it
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 60 * 60 * 24 * 365
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = "DENY"
SECURE_REFERRER_POLICY = "strict-origin-when-cross-origin"
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.middleware.csp.ContentSecurityPolicyMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
SECURE_CSP = {
"default-src": [CSP.SELF],
"script-src": [CSP.SELF, CSP.NONCE], # <script nonce="{{ csp_nonce }}">
"img-src": [CSP.SELF, "data:", "https://cdn.example.com"],
"frame-ancestors": [CSP.NONE],
}
Pitfalls
- Setting
SECURE_PROXY_SSL_HEADERwhen no trusted proxy sets the header (clients could spoof it). - Turning on long HSTS with
preloadbefore every subdomain serves HTTPS. - Allowing
'unsafe-inline'scripts in the CSP, which removes most of its XSS protection.
Variations
- Start with
SECURE_CSP_REPORT_ONLYto collect violations before enforcing. - Add the
cspcontext processor and use{{ csp_nonce }}on inline scripts.
Further reading: Content Security Policy in Django
Reference: https://docs.djangoproject.com/en/6.0/ref/csp/
More Django recipes
- Add a required column without downtime
- Add full-text search with PostgreSQL
- Add health checks and structured logging
- Avoid N+1 queries with select_related and prefetch_related
- Cache expensive queries and invalidate on change
- Call external APIs concurrently in async views
- Configure settings from environment variables
- Enforce rules with database constraints