Inhaltsverzeichnis
- Die Kurzfassung: CSRF vs. CORS vs. CSP im Überblick
- Aktueller Stand für Django-Projekte (Django 6.0, 5.2 LTS & 4.2)
- Warum CSRF, CORS und CSP in der Praxis so oft verwechselt werden
- CSRF in Django: Schutz vor gefälschten Anfragen in bestehenden Sessions
- CORS in Django: Der Browser-Türsteher für Cross-Origin-Requests
- CSP in Django: Content Security Policy als wirksamer XSS-Schutz
- Architektur-Leitfaden: Wie CSRF, CORS und CSP zusammenspielen
- Vergleichstabelle: CSRF vs. CORS vs. CSP auf einen Blick
- Die 5 häufigsten Sicherheitsfehler in Django-Projekten
- Production-Ready Checklist: Sicherheitseinstellungen für settings.py
- Fazit: Defense-in-Depth für moderne Django-Anwendungen
- Häufig gestellte Fragen (FAQ)
Über den Autor
14.10.2026
Web Security in Django meisternDjango Security: CSRF, CORS und CSP sauber konfigurieren
Wer schon einmal einen CORS-Fehler im Browser gesehen hat, kennt den typischen Reflex: kurz Access-Control-Allow-Origin: * setzen, Seite neu laden, weitermachen. Das Problem dabei: Man löst damit selten die eigentliche Ursache, sondern verschiebt lediglich riskante Sicherheitsgrenzen. In modernen Django-Projekten werden CSRF, CORS und CSP ständig verwechselt – obwohl sie völlig unterschiedliche Schutzziele im Web verfolgen. In diesem Leitfaden erfährst du, wie die drei Mechanismen funktionieren, wie sie zusammenspielen und wie du sie in Django 6.0, modernen SPAs und REST APIs produktionssicher konfigurierst.

Vorausgesetzte Kenntnisse
Folgende Kenntnisse solltest du haben, um den Artikel ideal zu nutzen:- Django-Grundlagen (
settings.py, Views, Middleware-Architektur) - HTTP-Grundlagen (Request/Response-Header, Cookies wie
SameSite&HttpOnly, Methoden wiePOST&OPTIONS) - Same-Origin-Policy (SOP) im Browser
- Grundlagen moderner Webarchitekturen (REST APIs, SPAs mit Vue.js / Nuxt oder React)
- Basiswissen Web-Sicherheit (OWASP Top 10, insb. CSRF und XSS)
Solltest du Fragen haben oder dir etwas unklar sein, kannst du gerne die Kommentarfunktion unter dem Artikel nutzen.
Django bringt von Haus aus exzellente Sicherheitsmechanismen mit. Als erfahrene Python- und Django-Agentur sehen wir in Sicherheitsreviews jedoch immer wieder: Das eigentliche Risiko sitzt fast nie im Framework selbst, sondern in der Konfiguration. Typische Fehlerquellen sind vorschnell gesetzte @csrf_exempt-Dekoratoren, übermäßig offene CORS-Einstellungen oder eine Content Security Policy (CSP), die am Ende durch Dutzende unsafe-inline-Ausnahmen wirkungslos gemacht wird.
Bringen wir Klarheit in das Thema und trennen die drei Säulen methodisch sauber voneinander.
Die Kurzfassung: CSRF vs. CORS vs. CSP im Überblick
Für eilige Entwickler und Architekten lässt sich der Kernunterschied in drei Sätzen zusammenfassen:
- CSRF (Cross-Site Request Forgery): Schützt deine Anwendung vor ungewollten Aktionen, die eine bösartige Website im Namen eines authentifizierten Benutzers an deinen Server sendet (Schreibschutz).
- CORS (Cross-Origin Resource Sharing): Bestimmt als Browser-Sicherheitsmechanismus, ob clientseitiges JavaScript von einer fremden Origin die Antworten deiner Anwendung überhaupt lesen darf (Leseschutz).
- CSP (Content Security Policy): Begrenzt als HTTP-Header, welche ausführbaren Inhalte und Ressourcen (JavaScript, Stylesheets, Bilder, Frames, Verbindungen) der Browser überhaupt laden und ausführen darf (Ausführungsschutz / XSS-Abwehr).
Wer diese drei Sicherheitskonzepte trennscharf unterscheidet, verhindert gravierende Fehlkonfigurationen, spart wertvolle Zeit beim Debugging und reduziert Tickets in agilen Projekten spürbar.
Aktueller Stand für Django-Projekte (Django 6.0, 5.2 LTS & 4.2)
Bevor wir in die Details einsteigen, ein Blick auf den aktuellen Versionsstand und Support-Zyklus im Django-Ökosystem:
- Django 6.0 ist die moderne Hauptversion und bringt ein lang ersehntes Highlight mit: integrierte Content Security Policy (CSP) direkt im Framework-Kern (
django.middleware.csp.ContentSecurityPolicyMiddleware). - Django 5.2 LTS ist die aktuelle Long-Term-Support-Version mit erweitertem Unternehmens-Support bis 2028.
- Django 4.2 LTS hat sein Support-Ende im April 2026 erreicht. Spätestens jetzt sollten bestehende Projekte zeitnah migriert werden.
- Kein zwingendes Drittanbieter-Paket mehr für CSP ab Django 6.0: Während ältere Versionen auf das bewährte Paket
django-cspangewiesen sind, nutzen neue Setups ab 6.0 die nativen Boardmittel.
Viele Anleitungen im Netz zeigen für CSP ausschließlich django-csp. Für Legacy- und 5.2-LTS-Projekte ist das weiterhin legitim, bei Neuentwicklungen auf Django 6.0 lohnt sich jedoch der direkte Einsatz der bordeigenen Implementierung.
Warum CSRF, CORS und CSP in der Praxis so oft verwechselt werden
In modernen Webarchitekturen treten diese drei Themen selten isoliert auf. Ein typisches Enterprise-Setup sieht heute oft so aus:
- Ein Backend auf Basis von Django mit Admin und ORM.
- Ein entkoppeltes Single-Page-Application-Frontend (z. B. mit React oder Vue.js & Nuxt), das unter einer eigenen Subdomain oder Origin gehostet wird.
- Eine REST API mit Django REST Framework (DRF) mit Session-Authentifizierung für interne Backoffice-Mitarbeiter und Bearer-Tokens für externe mobile Apps.
- Externe Drittanbieter-Dienste für Analytics, Sentry-Fehlerüberwachung oder Web-Fonts.
- Ein gehärteter Django-Adminbereich, der strikte Restriktionen erfordert, aber im Redaktionsalltag benutzbar bleiben muss.
Auf den ersten Blick scheint alles miteinander verknüpft zu sein. Zur präzisen Fehlerdiagnose genügen jedoch drei Leitfragen:
- Wird der Browser dazu verleitet, im Namen eines eingeloggten Nutzers eine schreibende Zustandsänderung auszuführen?
→ Hier greift der CSRF-Schutz. - Darf clientseitiges JavaScript von Origin A die API-Antwort von Origin B auslesen?
→ Hier greift die CORS-Richtlinie. - Darf der Browser dieses Skript, diesen Inline-Code oder diese externe Verbindung überhaupt laden und ausführen?
→ Hier greift die Content Security Policy (CSP).
Mit diesen drei Leitfragen lassen sich über 80 % aller Sicherheits- und CORS-Verwirrungen im Team sofort auflösen.
CSRF in Django: Schutz vor gefälschten Anfragen in bestehenden Sessions
Cross-Site Request Forgery (CSRF) ist ein Angriffsmuster, das auf browserbasierte Sitzungen und automatische Cookie-Übertragungen abzielt.
Der Angriffsvektor
Das Prinzip ist tückisch einfach: Ein Nutzer meldet sich bei deiner Django-Webseite an und erhält ein Session-Cookie. Ohne sich abzumelden, surft er auf einem zweiten Tab auf einer bösartigen Webseite evil.com. Diese Seite enthält ein verstecktes Formular oder ein JavaScript-Skript, das einen POST-Request an https://deine-app.de/api/account/delete/ abfeuert.
Weil der Browser bei Anfragen an deine-app.de die zugehörigen Session-Cookies automatisch im Header mitsendet, hält der Server die Anfrage ohne zusätzliche Härtung für legitim und löscht das Benutzerkonto.
Wie Django und CsrfViewMiddleware Requests absichern
Django liefert mit der CsrfViewMiddleware eine der robustesten Implementierungen überhaupt. Die Middleware prüft bei unsicheren HTTP-Methoden (POST, PUT, PATCH, DELETE), ob ein gültiger, maskierter CSRF-Token vorhanden ist.
In klassischen Django-Templates geschieht das über das Formular-Tag:
<form method="post" action="/profil/speichern/">
{% csrf_token %}
<button type="submit">Speichernbutton>
form>
Django validiert den im Formular übertragenen Token gegen das im Cookie (csrftoken) hinterlegte Geheimnis (Double-Submit-Cookie-Pattern mit Kryptomaske). Eine fremde Origin kann zwar einen Request absenden, hat wegen der Same-Origin-Policy des Browsers aber keinen lesenden Zugriff auf das Cookie oder das DOM deiner Anwendung – und kann den passenden Token daher nicht erraten.
Origin-Prüfung und CSRF_TRUSTED_ORIGINS seit Django 4.0
Seit Version 4.0 wertet Django bei unsicheren HTTP-Anfragen zusätzlich den HTTP-Header Origin (bzw. Referer) aus. Das bedeutet: Wenn Anfragen von einer externen Origin an deine Django-Views geschickt werden, verlangt Django zwingend einen Eintrag in CSRF_TRUSTED_ORIGINS.
Wichtig: Seit Django 4.0 müssen Einträge zwingend das Protokoll-Schema (
https://oderhttp://) enthalten:
# settings.py
CSRF_TRUSTED_ORIGINS = [
"https://app.example.com",
"https://admin.example.com",
"https://*.example.com", # Wildcards für Subdomains sind ab 4.0 zulässig
]
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SAMESITE = "Lax"
Wenn deine Django-Instanz hinter einem Reverse Proxy oder Ingress-Controller läuft (z. B. NGINX oder Traefik), muss SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") gesetzt sein. Andernfalls schlägt die CSRF-Prüfung fehl, weil Django eingehende Requests fälschlich als unsicheres HTTP einstuft.
AJAX und Fetch: X-CSRFToken im Header übergeben
Bei modernen SPAs oder JavaScript-Komponenten innerhalb desselben Ursprungs liest man den CSRF-Token aus dem Cookie aus und übergibt ihn im Request-Header X-CSRFToken:
// csrftoken aus Cookie extrahieren
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== "") {
const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === name + "=") {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie("csrftoken");
await fetch("/api/v1/profile/", {
method: "PATCH",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": csrftoken,
},
body: JSON.stringify({ bio: "Full-Stack Developer" }),
});
Django REST Framework (DRF): SessionAuth vs. TokenAuth
In Projekten mit dem Django REST Framework (DRF) entsteht an dieser Stelle die größte Verwirrung:
SessionAuthenticationim Einsatz: Hier greift DjangosCsrfViewMiddlewareuneingeschränkt. Wer Session-Cookies für die Authentifizierung nutzt, muss den CSRF-Token mitsenden!TokenAuthenticationoder JWT (Bearer Token): Wenn die Authentifizierung rein über denAuthorization: BearerHeader läuft und keine Session-Cookies im Browser verwendet werden, ist die Anwendung immun gegen CSRF.
Der Griff zum @csrf_exempt-Dekorator über ganze API-ViewSets ist in 95 % der Fälle ein gefährliches Antipattern. Wenn kein Session-Cookie verwendet wird, sollte stattdessen die authentication_classes-Liste in DRF angepasst werden, anstatt Sicherheitsprüfungen pauschal abzuschalten.
CORS in Django: Der Browser-Türsteher für Cross-Origin-Requests
Cross-Origin Resource Sharing (CORS) ist ein W3C-Standard, der es Browsern ermöglicht, kontrollierte Ausnahmen von der Same-Origin-Policy zu machen.
Viele Entwickler glauben irrtümlich, CORS sei eine serverseitige Firewall. Das ist falsch:
curlignoriert CORS vollständig.- Server-to-Server-Kommunikation ignoriert CORS vollständig.
- Python-Skripte mit
requestsignorieren CORS vollständig.
CORS beantwortet ausschließlich eine browserinterne Frage:
Darf clientseitiges JavaScript von Origin A die Antwort lesen, die von Origin B zurückkam?
Ausführliche Details zu Container- und Proxy-Setups findest du in unserem separaten Praxisleitfaden zu Django-CORS in Produktion.
Was definiert eine Origin?
Zwei URLs haben dieselbe Origin, wenn Protokoll, Host und Port identisch sind:
http://localhost:3000(Frontend-Dev-Server)http://localhost:8000(Django-Backend-Server)
Da sich der Port unterscheidet, liegt ein Cross-Origin-Request vor. Der Browser blockiert den Lesezugriff auf die Antwort, es sei denn, Django signalisiert explizit über HTTP-Header, dass dieser Ursprung zugriffsberechtigt ist.
Der Preflight-Request (OPTIONS)
Bei nicht-einfachen HTTP-Requests (z. B. bei Content-Type: application/json oder benutzerdefinierten Headern) sendet der Browser automatisch eine Vorabanfrage mit der Methode OPTIONS. Erst wenn der Server diese mit den passenden Access-Control-Allow-*-Headern beantwortet, führt der Browser den eigentlichen GET-, POST- oder PUT-Request aus.
Saubere Konfiguration mit django-cors-headers
Im Django-Ökosystem ist die Bibliothek django-cors-headers der De-facto-Standard:
pip install django-cors-headers
In den Einstellungen muss die Middleware zwingend an oberster Stelle platziert werden:
# settings.py
INSTALLED_APPS = [
# ...
"corsheaders",
"django.contrib.auth",
"django.contrib.contenttypes",
# ...
]
MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware", # Muss ganz nach oben!
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
# ...
]
# Explizite Freigabe einzelner Origins:
CORS_ALLOWED_ORIGINS = [
"https://app.example.com",
"https://kunde.example.com",
]
# Erlaubt das Mitsenden von Cookies / Credentials
CORS_ALLOW_CREDENTIALS = True
Warum CORS_ALLOW_ALL_ORIGINS = True in Produktion ein No-Go ist
Das Setzen von CORS_ALLOW_ALL_ORIGINS = True (bzw. Access-Control-Allow-Origin: *) hebelt den Browserschutz für all deine Endpunkte aus. Jede x-beliebige Seite im Netz kann per Hintergrund-JavaScript Daten aus deiner API auslesen.
Noch kritischer: Sobald CORS_ALLOW_CREDENTIALS = True gesetzt ist, verbietet die Browser-Spezifikation den Wildcard-Stern * ohnehin. Hier müssen explizite Domains via CORS_ALLOWED_ORIGINS hinterlegt werden.
Das Zusammenspiel: CORS_ALLOWED_ORIGINS vs. CSRF_TRUSTED_ORIGINS
Wenn deine Vue- oder React-App auf https://app.example.com liegt und dein Django-Backend auf https://api.example.com mit Session-Cookies arbeitet, müssen beide Einstellungen Hand in Hand konfiguriert werden:
# Erlaubt dem Browser, Antworten der API zu lesen:
CORS_ALLOWED_ORIGINS = [
"https://app.example.com",
]
# Weist Django an, Cross-Origin POST-Requests im CSRF-Check zu akzeptieren:
CSRF_TRUSTED_ORIGINS = [
"https://app.example.com",
]
CORS_ALLOWED_ORIGINSsagt dem Browser: Diese Origin darf die Antwort verarbeiten.CSRF_TRUSTED_ORIGINSsagt Django: Anfragen von diesem fremden Ursprung dürfen schreibende Operationen ausführen.
CSP in Django: Content Security Policy als wirksamer XSS-Schutz
Wenn es um die Absicherung gegen Cross-Site Scripting (XSS) und Code-Injection geht, ist die Content Security Policy (CSP) das mächtigste Werkzeug moderner Browser.
Selbst wenn Django Templates standardmäßig automatisch escaped: Benutzereingaben in Rich-Text-Editoren, unvorsichtiges mark_safe(), kompromittierte npm-Pakete oder fehlerhafte Third-Party-Widgets können jederzeit Sicherheitslücken aufreißen. CSP fungiert hier als verlässliche zweite Verteidigungslinie (Defense in Depth).
Die Neuerung: Eingebaute CSP-Unterstützung ab Django 6.0
Seit Django 6.0 ist CSP fester Bestandteil des Frameworks. Für neue Projekte entfällt die Notwendigkeit für externe Pakete.
Die Aktivierung erfolgt über die neue Middleware:
# settings.py
from django.utils.csp import CSP
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.middleware.csp.ContentSecurityPolicyMiddleware", # Neu in Django 6.0!
# ...
]
SECURE_CSP = {
"default-src": [CSP.SELF],
"script-src": [CSP.SELF, CSP.NONCE],
"style-src": [CSP.SELF],
"img-src": [CSP.SELF, "data:", "https:"],
"font-src": [CSP.SELF, "https:"],
"connect-src": [CSP.SELF, "https://api.example.com"],
"object-src": [CSP.NONE],
"base-uri": [CSP.NONE],
"frame-ancestors": [CSP.NONE],
"form-action": [CSP.SELF],
}
Mit diesem Basis-Setup verhindert der Browser sofort das Laden bösartiger externer Skripte, unterbindet Clickjacking (frame-ancestors: 'none') und blockiert Formularumleitungen auf fremde Ziele.
Best Practice: Report-Only-Modus vor dem Enforcing
Eine strikte CSP kann auf bestehenden Webseiten versehentlich legitime Skripte oder Widgets brechen. Daher empfiehlt es sich, CSP zunächst im Report-Only-Modus zu testen:
# settings.py
from django.utils.csp import CSP
# Sendet Content-Security-Policy-Report-Only Header
SECURE_CSP_REPORT_ONLY = {
"default-src": [CSP.SELF],
"script-src": [CSP.SELF, CSP.NONCE],
"style-src": [CSP.SELF],
"img-src": [CSP.SELF, "data:", "https:"],
"report-uri": "/csp-violations-collector/",
}
Der Browser führt in diesem Modus alle Ressourcen wie gewohnt aus, sendet aber bei Verstößen einen JSON-Bericht an deine Reporting-URL. Sobald alle legitimen Ressourcen erfasst sind, wechselst du auf SECURE_CSP.
Inline-JavaScript sauber mit Nonces absichern
Die Versuchung ist groß, bei Skript-Problemen einfach 'unsafe-inline' zur CSP hinzuzufügen. Damit verpufft jedoch der Großteil der XSS-Schutzwirkung.
Die empfohlene Lösung sind kryptografische Nonces (Number used once). Django generiert pro HTTP-Request eine Zufallszeichenkette, die sowohl im HTTP-Header als auch im HTML-Tag stehen muss:
In den Template-Context-Processors aktivieren:
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"OPTIONS": {
"context_processors": [
# ...
"django.template.context_processors.csp", # Stellt csp_nonce bereit
],
},
},
]
Im Template:
{{ app_config|json_script:"app-config-data" }}
<script nonce="{{ csp_nonce }}">
const appConfig = JSON.parse(
document.getElementById("app-config-data").textContent
);
console.log("App initialisiert mit Nonce-Schutz");
script>
Tipp: Verwende immer Djangos eingebautes
json_script-Filter-Tag, um Variablen an das Frontend zu übergeben. Das verhindert XSS-Lücken durch fehlerhafte JavaScript-String-Interpolation.
CSP in Django 5.2 LTS und älter mit django-csp 4.0
Für Projekte auf Django 5.2 LTS oder Django 4.2 bleibt das Paket django-csp die erste Wahl. Beachte jedoch, dass django-csp mit Version 4.0 eine moderne Konfigurationsstruktur eingeführt hat:
# settings.py (für django-csp 4.0+)
from csp.constants import SELF, NONCE, NONE
MIDDLEWARE = [
# ...
"csp.middleware.CSPMiddleware",
]
CONTENT_SECURITY_POLICY = {
"DIRECTIVES": {
"default-src": [SELF],
"script-src": [SELF, NONCE],
"style-src": [SELF],
"object-src": [NONE],
"base-uri": [NONE],
},
}
Veraltete Tutorials zeigen noch alte Settings wie CSP_DEFAULT_SRC = ("'self'",). Diese Schreibweise ist in Version 4.0 deprecated.
Architektur-Leitfaden: Wie CSRF, CORS und CSP zusammenspielen
Der Praxisnutzen wird besonders deutlich, wenn man typische Architekturmodelle nebeneinanderlegt:
Szenario 1: Klassischer Django-Monolith mit Server-Side-Templates
- CSRF: Ja, zwingend. Jedes schreibende
nutzt{% csrf_token %}. - CORS: Nein. Da Frontend und Backend auf derselben Origin laufen (
same-origin), wird kein CORS benötigt. - CSP: Ja, sehr empfohlen. Schützt den Admin-Bereich, CMS-Inhalte und Formulare vor XSS.
Szenario 2: Entkoppelte SPA (React / Vue / Nuxt) mit Session-Cookies
- CSRF: Ja, zwingend. Der Token muss per
X-CSRFToken-Header im JavaScript-Request mitgeschickt werden.CSRF_TRUSTED_ORIGINSmuss die SPA-Domain enthalten. - CORS: Ja, zwingend.
CORS_ALLOWED_ORIGINSmuss die SPA-Domain freigeben undCORS_ALLOW_CREDENTIALS = Truemuss aktiv sein. - CSP: Ja. Sowohl im Django-Backend (für API- und Admin-Routen) als auch im SPA-Hosting sollten restriktive CSP-Header ausgeliefert werden.
Szenario 3: Öffentliche REST API mit Token- oder Bearer-Authentifizierung
- CSRF: Nein. Solange keine Cookies ausgewertet werden, besteht kein CSRF-Risiko.
- CORS: Ja, sofern Web-Browser die API direkt von externen Seiten per Fetch oder AJAX ansprechen dürfen.
- CSP: Für reine JSON-Antworten nicht anwendbar, für API-Dokumentation (Swagger / ReDoc) jedoch sinnvoll.
Vergleichstabelle: CSRF vs. CORS vs. CSP auf einen Blick
Die folgende Matrix bietet eine schnelle Entscheidungshilfe für Code-Reviews und Architekturentwürfe:
| Kriterium | CSRF (Cross-Site Request Forgery) | CORS (Cross-Origin Resource Sharing) | CSP (Content Security Policy) |
|---|---|---|---|
| Primäres Schutzziel | Verhindert ungewollte Aktionen im Namen authentifizierter Nutzer | Kontrolliert Lesezugriffe auf Antworten zwischen verschiedenen Domains | Verhindert XSS, Clickjacking und nicht autorisierte Code-Ausführung |
| Schutzrichtung | Inbound (Schreibanfragen) | Outbound (Leseantworten) | Client-Execution (Browser-Laufzeit) |
| Durchsetzungsinstanz | Server & Middleware (validiert Token/Origin) | Webbrowser (prüft Access-Control-Header) | Webbrowser (blockiert nicht deklarierte Ressourcen) |
| Typischer Angriff | Phishing-Seite löst unbemerkt Aktionen im Bankkonto / CMS aus | Bösartige Domain liest vertrauliche Daten aus fremder API aus | Angreifer schleust schädliches JavaScript ein (Data Theft, Keylogging) |
| Relevante Django-Komponenten | CsrfViewMiddleware, CSRF_TRUSTED_ORIGINS, {% csrf_token %} | Paket django-cors-headers, CORS_ALLOWED_ORIGINS | Django 6.0 SECURE_CSP oder Paket django-csp |
| Häufigster Denkfehler | "Meine API braucht niemals CSRF-Schutz" | "CORS schützt meinen Server vor Hacker-Angriffen" | "CSP ist optional, Escaping im Template reicht" |
Die 5 häufigsten Sicherheitsfehler in Django-Projekten
1. @csrf_exempt als schneller Workaround
Wenn Entwickler auf 403 Forbidden (CSRF verification failed) stoßen, wird häufig @csrf_exempt auf Views gesetzt. Das ist eine brandgefährliche Scheinlösung. Die korrekte Lösung: Prüfe das Authentifizierungsmodell, sende X-CSRFToken im Header mit oder konfiguriere CSRF_TRUSTED_ORIGINS sauber.
2. CORS_ALLOW_ALL_ORIGINS = True in Produktionsumgebungen
Entwickler aktivieren diese Einstellung lokal und vergessen sie vor dem Go-Live. In Produktion gehören ausschließlich explizite Origins in CORS_ALLOWED_ORIGINS.
3. CSP aktivieren und sofort mit unsafe-inline kapitulieren
Sobald Styles oder Skripte blockiert werden, greifen viele Teams zu 'unsafe-inline' und 'unsafe-eval'. Damit verliert CSP rund 90 % seines Sicherheitsnutzens. Setze stattdessen auf kryptografische Nonces (CSP.NONCE) und Djangos json_script.
4. CSRF_TRUSTED_ORIGINS ohne URL-Schema angeben
Seit Django 4.0 führt CSRF_TRUSTED_ORIGINS = ["example.com"] zu Validierungsfehlern. Das Protokoll https:// ist zwingend erforderlich (["https://example.com"]).
5. python manage.py check --deploy im Release-Prozess überspringen
Django bietet eine integrierte Prüfung für produktionsrelevante Sicherheitseinstellungen. Dieser Check sollte als fester Bestandteil in jede CI/CD-Pipeline integriert sein.
Production-Ready Checklist: Sicherheitseinstellungen für settings.py
Für einen soliden Mindeststandard in Produktionsumgebungen gehören folgende Direktiven in deine Konfiguration:
# settings.py - Production Security Baseline
DEBUG = False
# HTTPS & Cookie-Sicherheit
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = False # Muss False sein, wenn JS den Token für AJAX auslesen muss
CSRF_COOKIE_SAMESITE = "Lax"
SESSION_COOKIE_SAMESITE = "Lax"
# Trusted Origins für CSRF
CSRF_TRUSTED_ORIGINS = [
"https://app.example.com",
"https://admin.example.com",
]
# HTTP Strict Transport Security (HSTS)
SECURE_HSTS_SECONDS = 31536000 # 1 Jahr
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Browser-Schutzheader
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = "DENY"
# Reverse-Proxy Konfiguration (z. B. hinter NGINX / Kubernetes Ingress)
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
Vor jedem Deployment empfiehlt sich die automatisierte Sicherheitsprüfung im Terminal:
python manage.py check --deploy
Dieser Befehl deckt fehlende Sicherheits-Flags, offene Cookies und riskante Debug-Einstellungen zuverlässig auf. Suchst du Unterstützung bei der Architektur oder Absicherung deiner Plattform? Erfahre mehr über unsere Cloud-Sicherheitsberatung und maßgeschneiderte Enterprise-Software-Entwicklung.
Fazit: Defense-in-Depth für moderne Django-Anwendungen
CSRF, CORS und CSP mögen auf den ersten Blick wie ein zusammenhängendes Akronym-Dickicht wirken. In der Praxis erfüllen sie jedoch drei klar getrennte Schutzfunktionen:
- CSRF fragt: Wurde dieser schreibende Request wirklich bewusst und autorisiert von meiner Anwendung ausgelöst?
- CORS fragt: Darf ein fremdes Browser-JavaScript die Daten dieser API-Antwort verarbeiten?
- CSP fragt: Welche Skripte und Ressourcen darf der Browser innerhalb dieser Webseite überhaupt ausführen?
Wer diese drei Hebel versteht, trifft fundierte Architekturentscheidungen und baut robuste, enterprise-fähige Webanwendungen. Mit der Einführung nativer CSP-Funktionen in Django 6.0 wird das Framework noch vollständiger – und macht externe Workarounds in Zukunft weitgehend überflüssig.
Häufig gestellte Fragen (FAQ)
Was ist der Unterschied zwischen CSRF, CORS und CSP in Django?
CSRF schützt vor ungewollten schreibenden Aktionen im Namen eines authentifizierten Benutzers. CORS steuert als Browser-Richtlinie, ob clientseitiges JavaScript Antworten von einer fremden Origin lesen darf. CSP begrenzt als Content Security Policy, welche Skripte, Styles und Ressourcen der Browser überhaupt ausführen und laden darf.
Was ist der Unterschied zwischen CSRF_TRUSTED_ORIGINS und CORS_ALLOWED_ORIGINS?
CORS_ALLOWED_ORIGINS regelt im Browser, wer Responses lesen darf (Access-Control-Allow-Origin). CSRF_TRUSTED_ORIGINS weist Django serverseitig an, unsichere schreibende HTTP-Requests (POST, PUT, DELETE) von dieser Origin trotz Cross-Origin-Status zu akzeptieren. Beide Einstellungen erfüllen getrennte Sicherheitsprüfungen und sind nicht gegenseitig austauschbar.
Wie funktioniert die neue integrierte CSP in Django 6.0?
Ab Django 6.0 ist Content Security Policy direkt in Django integriert über django.middleware.csp.ContentSecurityPolicyMiddleware und das Setting SECURE_CSP (oder SECURE_CSP_REPORT_ONLY für den Testbetrieb). Ein externes Paket wie django-csp ist für Standardkonfigurationen nicht mehr zwingend nötig.
Wann benötigt eine Django REST Framework (DRF) API CSRF-Schutz?
CSRF-Schutz wird immer dann benötigt, wenn die API SessionAuthentication mit browserbasierten Session-Cookies nutzt. Bei reinen stateless APIs mit Token- oder Bearer-Authentifizierung im HTTP-Authorization-Header ist CSRF-Schutz in der Regel nicht erforderlich.
Warum ist CORS_ALLOW_ALL_ORIGINS = True in der Produktion gefährlich?
CORS_ALLOW_ALL_ORIGINS = True erlaubt jeder beliebigen Website im Internet, Antworten deiner API über Browser-JavaScript auszulesen. Werden zudem Credentials (Cookies, Authorization-Header) übertragen, hebelt ein Wildcard-CORS grundlegende Browser-Isolationsmechanismen aus und gefährdet sensible Benutzerdaten.
Wie übergebe ich den Django CSRF-Token in AJAX- und Fetch-Requests?
Der Token wird aus dem Cookie (standardmäßig csrftoken) per JavaScript ausgelesen und im HTTP-Request-Header X-CSRFToken mitgeschickt. Django liest diesen Header in CsrfViewMiddleware automatisch aus und validiert den Request.
Hast du noch Fragen oder eine Meinung? Mit deinem GitHub Account kannst Du es uns wissen lassen...
Was unsere Kunden über uns sagen
- Ofa Bamberg GmbHB2B Online-Shop | B2C Website | Hosting | Betreuung | Security
- Ludwig-Maximilians-Universität MünchenPlattformentwicklung | Hosting | Betreuung | APIs | Website
Blueshoe hat unsere Forschungsdatenplattform Munich Media Monitoring (M3) entwickelt und uns hervorragend dabei beraten. Das Team hat unsere Anforderungen genau verstanden und sich aktiv in die Ausgestaltung der Software und der Betriebsumgebung eingebracht. Wir sind froh, dass auch Wartung und weiterführender Support in Blueshoes Händen liegen.
- Deutsches MuseumDigitalisierung | Beratung | Datenbank-Optimierung | GraphQL | CMSFoto: Anne Göttlicher
Im Rahmen eines komplexen Digitalisierungsprojekts für unsere Exponate-Datenbank war Blueshoe ein äußerst verlässlicher Partner. Sie haben uns nicht nur während des gesamten Projekts hervorragend beraten, sondern unsere Anforderungen perfekt umgesetzt. Dank ihrer Arbeit ist unsere Datenbank nun ein bedeutender Mehrwert für die weltweite wissenschaftliche Forschung.
- Fonds Finanz Maklerservice GmbHPlattformentwicklung | Prozess-Systeme | Hosting | Betreuung | Zertifikate | Website© Fonds Finanz Maklerservice GmbH
Blueshoe ist unsere verlängerte Werkbank für Entwicklung, Wartung und Support unserer Weiterbildungs- und Zertifizierungsplattformen. Das Team hat sich gründlich in unsere Abläufe eingearbeitet, und wir freuen uns, Blueshoe als zuverlässigen Partner an unserer Seite zu haben.
- Technische Universität HamburgPlattformentwicklung | Beratung | Prozess-Systeme | Hosting | Website
Seit 2019 unterstützt uns die Blueshoe GmbH tatkräftig bei der Entwicklung und Weiterentwicklung des "Digital Learning Lab" und der "Digital Learning Tools". Dank ihrer Beratung konnten wir von Anfang an auf eine zukunftssichere, moderne technische Struktur setzen. Die Zusammenarbeit ist reibungslos, und wir fühlen uns rundum gut betreut. Und davon profitieren dann auch die Lehrkräfte in Hamburg.


