Support CSP intégré dans Django 6.0

Django 6.0 ajoute un support natif des en-têtes Content Security Policy (CSP). Il n'est plus nécessaire d'installer django-csp : la configuration se fait directement dans settings.py et un middleware gère automatiquement les en-têtes et les nonces pour les scripts inline.

Configuration

On active le middleware CSP et on configure les directives dans settings.py. Django génère automatiquement un nonce unique par requête pour autoriser les scripts inline de confiance.

python
# settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.middleware.csp.CSPMiddleware',  # nouveau
    ...
]

CONTENT_SECURITY_POLICY = {
    'default-src': ["'self'"],
    'script-src': ["'self'", "'nonce'"],  # nonce auto-géré
    'style-src': ["'self'", "https://fonts.googleapis.com"],
    'img-src': ["'self'", "data:"],
    'font-src': ["'self'", "https://fonts.gstatic.com"],
    'connect-src': ["'self'"],
}

# Mode report-only pour tester sans bloquer :
CONTENT_SECURITY_POLICY_REPORT_ONLY = True
CONTENT_SECURITY_POLICY_REPORT_URI = '/csp-report/'

Scripts inline avec nonce

Dans les templates, le tag {% csp_nonce %} insère le nonce unique de la requête. Seuls les scripts portant ce nonce sont autorisés à s'exécuter.

htmldjango
{# templates/base.html #}
{% load csp %}
<!DOCTYPE html>
<html>
<head>
  <title>Mon site sécurisé</title>
  {# Script inline autorisé grâce au nonce #}
  <script nonce="{% csp_nonce %}">
    console.log('Ce script est autorisé par CSP');
  </script>
</head>
<body>
  {# Un script sans nonce sera bloqué par le navigateur #}
  {{ content }}
</body>
</html>

{# En-tête HTTP généré automatiquement :
   Content-Security-Policy: default-src 'self';
   script-src 'self' 'nonce-abc123def456'; ... #}

Sources