Fortgeschritten

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

CSRF schützt vor ungewollten Aktionen im Namen eines eingeloggten Nutzers, CORS regelt Lesezugriffe im Browser und CSP verhindert XSS. Wer diese drei Bausteine sauber trennt, baut wirklich sichere Django-Apps.
Zuletzt geändert:14.10.2026

DjangoSicherheitEntwicklungAPIPython

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.

Django Security: CSRF, CORS und CSP sauber konfigurieren

Vorausgesetzte Kenntnisse

Folgende Kenntnisse solltest du haben, um den Artikel ideal zu nutzen:

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:

  1. 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).
  2. Django 5.2 LTS ist die aktuelle Long-Term-Support-Version mit erweitertem Unternehmens-Support bis 2028.
  3. Django 4.2 LTS hat sein Support-Ende im April 2026 erreicht. Spätestens jetzt sollten bestehende Projekte zeitnah migriert werden.
  4. Kein zwingendes Drittanbieter-Paket mehr für CSP ab Django 6.0: Während ältere Versionen auf das bewährte Paket django-csp angewiesen 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:

  1. Wird der Browser dazu verleitet, im Namen eines eingeloggten Nutzers eine schreibende Zustandsänderung auszuführen?
    → Hier greift der CSRF-Schutz.
  2. Darf clientseitiges JavaScript von Origin A die API-Antwort von Origin B auslesen?
    → Hier greift die CORS-Richtlinie.
  3. 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:// oder http://) 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:

  • SessionAuthentication im Einsatz: Hier greift Djangos CsrfViewMiddleware uneingeschränkt. Wer Session-Cookies für die Authentifizierung nutzt, muss den CSRF-Token mitsenden!
  • TokenAuthentication oder JWT (Bearer Token): Wenn die Authentifizierung rein über den Authorization: Bearer Header 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:

  • curl ignoriert CORS vollständig.
  • Server-to-Server-Kommunikation ignoriert CORS vollständig.
  • Python-Skripte mit requests ignorieren 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_ORIGINS sagt dem Browser: Diese Origin darf die Antwort verarbeiten.
  • CSRF_TRUSTED_ORIGINS sagt 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_ORIGINS muss die SPA-Domain enthalten.
  • CORS: Ja, zwingend. CORS_ALLOWED_ORIGINS muss die SPA-Domain freigeben und CORS_ALLOW_CREDENTIALS = True muss 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:

KriteriumCSRF (Cross-Site Request Forgery)CORS (Cross-Origin Resource Sharing)CSP (Content Security Policy)
Primäres SchutzzielVerhindert ungewollte Aktionen im Namen authentifizierter NutzerKontrolliert Lesezugriffe auf Antworten zwischen verschiedenen DomainsVerhindert XSS, Clickjacking und nicht autorisierte Code-Ausführung
SchutzrichtungInbound (Schreibanfragen)Outbound (Leseantworten)Client-Execution (Browser-Laufzeit)
DurchsetzungsinstanzServer & Middleware (validiert Token/Origin)Webbrowser (prüft Access-Control-Header)Webbrowser (blockiert nicht deklarierte Ressourcen)
Typischer AngriffPhishing-Seite löst unbemerkt Aktionen im Bankkonto / CMS ausBösartige Domain liest vertrauliche Daten aus fremder API ausAngreifer schleust schädliches JavaScript ein (Data Theft, Keylogging)
Relevante Django-KomponentenCsrfViewMiddleware, CSRF_TRUSTED_ORIGINS, {% csrf_token %}Paket django-cors-headers, CORS_ALLOWED_ORIGINSDjango 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

/img/homepage/testimonial_bg.svg
Ofa Bamberg GmbHFabian Bohnen
Ludwig-Maximilians-Universität MünchenProf. Dr. Mario Haim
Deutsches MuseumGeorg Hohmann
Fonds Finanz Maklerservice GmbHNorbert Porazik
Technische Universität HamburgSören Schütt-Sayed
  • Ofa Bamberg GmbH
    Ofa Bamberg GmbH
    B2B Online-Shop | B2C Website | Hosting | Betreuung | Security
    Fabian Bohnen
    © Ofa Bamberg GmbH
    Seit zehn Jahren betreut Blueshoe unsere Webapplikationen – vom Onlineshop bis hin zum Web‑Umfeld. Die Zusammenarbeit ist stets kompetent, verlässlich und vorausschauend. Blueshoe ist für uns ein Partner, auf den wir uns jederzeit verlassen können.
    Fabian BohnenGeschäftsführer
  • Ludwig-Maximilians-Universität München
    Ludwig-Maximilians-Universität München
    Plattformentwicklung | Hosting | Betreuung | APIs | Website
    Prof. Dr. Mario Haim
    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.
    Prof. Dr. Mario HaimLehrstuhlinhaber, Institut für Kommunikationswissenschaft und Medienforschung
  • Deutsches Museum
    Deutsches Museum
    Digitalisierung | Beratung | Datenbank-Optimierung | GraphQL | CMS
    Georg Hohmann
    Foto: 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.
    Georg HohmannLeiter Deutsches Museum Digital
  • Fonds Finanz Maklerservice GmbH
    Fonds Finanz Maklerservice GmbH
    Plattformentwicklung | Prozess-Systeme | Hosting | Betreuung | Zertifikate | Website
    Norbert Porazik
    © 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.
    Norbert PorazikGründer und Geschäftsführer
  • Technische Universität Hamburg
    Technische Universität Hamburg
    Plattformentwicklung | Beratung | Prozess-Systeme | Hosting | Website
    Sören Schütt-Sayed
    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.
    Sören Schütt-SayedOberingenieur