---
title: "Django Security: CSRF, CORS und CSP sauber konfigurieren"
description: "CSRF, CORS und CSP in Django verstehen und sicher konfigurieren: Unterschiede, Best Practices für Django 6.0 & REST APIs sowie typische Fehler vermeiden."
canonical_url: "https://www.blueshoe.de/blog/django-security-csrf/"
---

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](/img/blogs/cors.webp)

<global-blog-level-info>

- [Django-Grundlagen](https://docs.djangoproject.com/de/) (`settings.py`, Views, [Middleware-Architektur](https://docs.djangoproject.com/en/stable/topics/http/middleware/))
- HTTP-Grundlagen (Request/Response-Header, Cookies wie `SameSite` & `HttpOnly`, Methoden wie `POST` & `OPTIONS`)
- [Same-Origin-Policy (SOP)](https://developer.mozilla.org/de/docs/Web/Security/Same-origin_policy) im Browser
- Grundlagen moderner Webarchitekturen (REST APIs, SPAs mit [Vue.js / Nuxt](/technologien/vuejs-nuxt/) oder React)
- Basiswissen Web-Sicherheit ([OWASP Top 10](https://owasp.org/Top10/de/), insb. [CSRF](https://owasp.org/www-community/attacks/csrf) und [XSS](https://owasp.org/www-community/attacks/xss/))

Solltest du Fragen haben oder dir etwas unklar sein, kannst du gerne die Kommentarfunktion unter dem Artikel nutzen.

</global-blog-level-info>

Django bringt von Haus aus exzellente Sicherheitsmechanismen mit. Als [erfahrene Python- und Django-Agentur](/technologien/python-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](/blog/agiles-projektmanagement-backlog/) 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](/technologien/vuejs-nuxt/)), das unter einer eigenen Subdomain oder Origin gehostet wird.
- Eine [REST API mit Django REST Framework (DRF)](/loesungen/api-entwicklung/) 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?**<br />


→ Hier greift der **CSRF-Schutz**.
2. **Darf clientseitiges JavaScript von Origin A die API-Antwort von Origin B auslesen?**<br />


→ Hier greift die **CORS-Richtlinie**.
3. **Darf der Browser dieses Skript, diesen Inline-Code oder diese externe Verbindung überhaupt laden und ausführen?**<br />


→ 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:

```html
<form method="post" action="/profil/speichern/">
  {% csrf_token %}
  <!-- Formularfelder -->
  <button type="submit">Speichern</button>
</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:

```python
# 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`:

```javascript
// 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 <Token>` 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:<br />

**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](/blog/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:

```bash
pip install django-cors-headers
```

In den Einstellungen muss die Middleware zwingend an oberster Stelle platziert werden:

```python
# 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:

```python
# 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:

```python
# 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:

```python
# 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:

```python
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "OPTIONS": {
            "context_processors": [
                # ...
                "django.template.context_processors.csp",  # Stellt csp_nonce bereit
            ],
        },
    },
]
```

Im Template:

```html
<!-- Daten sicher als JSON übergeben (verhindert Inline-Script-Injections) -->
{{ app_config|json_script:"app-config-data" }}

<!-- Skript mit Nonce ausführen -->
<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:

```python
# 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 `<form>` 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:

<table>
<thead>
  <tr>
    <th align="left">
      Kriterium
    </th>
    
    <th align="left">
      CSRF (Cross-Site Request Forgery)
    </th>
    
    <th align="left">
      CORS (Cross-Origin Resource Sharing)
    </th>
    
    <th align="left">
      CSP (Content Security Policy)
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td align="left">
      <strong>
        Primäres Schutzziel
      </strong>
    </td>
    
    <td align="left">
      Verhindert ungewollte Aktionen im Namen authentifizierter Nutzer
    </td>
    
    <td align="left">
      Kontrolliert Lesezugriffe auf Antworten zwischen verschiedenen Domains
    </td>
    
    <td align="left">
      Verhindert XSS, Clickjacking und nicht autorisierte Code-Ausführung
    </td>
  </tr>
  
  <tr>
    <td align="left">
      <strong>
        Schutzrichtung
      </strong>
    </td>
    
    <td align="left">
      Inbound (Schreibanfragen)
    </td>
    
    <td align="left">
      Outbound (Leseantworten)
    </td>
    
    <td align="left">
      Client-Execution (Browser-Laufzeit)
    </td>
  </tr>
  
  <tr>
    <td align="left">
      <strong>
        Durchsetzungsinstanz
      </strong>
    </td>
    
    <td align="left">
      <strong>
        Server & Middleware
      </strong>
      
       (validiert Token/Origin)
    </td>
    
    <td align="left">
      <strong>
        Webbrowser
      </strong>
      
       (prüft Access-Control-Header)
    </td>
    
    <td align="left">
      <strong>
        Webbrowser
      </strong>
      
       (blockiert nicht deklarierte Ressourcen)
    </td>
  </tr>
  
  <tr>
    <td align="left">
      <strong>
        Typischer Angriff
      </strong>
    </td>
    
    <td align="left">
      Phishing-Seite löst unbemerkt Aktionen im Bankkonto / CMS aus
    </td>
    
    <td align="left">
      Bösartige Domain liest vertrauliche Daten aus fremder API aus
    </td>
    
    <td align="left">
      Angreifer schleust schädliches JavaScript ein (Data Theft, Keylogging)
    </td>
  </tr>
  
  <tr>
    <td align="left">
      <strong>
        Relevante Django-Komponenten
      </strong>
    </td>
    
    <td align="left">
      <code>
        CsrfViewMiddleware
      </code>
      
      , <code>
        CSRF_TRUSTED_ORIGINS
      </code>
      
      , <code>
        {% csrf_token %}
      </code>
    </td>
    
    <td align="left">
      Paket <code>
        django-cors-headers
      </code>
      
      , <code>
        CORS_ALLOWED_ORIGINS
      </code>
    </td>
    
    <td align="left">
      Django 6.0 <code>
        SECURE_CSP
      </code>
      
       oder Paket <code>
        django-csp
      </code>
    </td>
  </tr>
  
  <tr>
    <td align="left">
      <strong>
        Häufigster Denkfehler
      </strong>
    </td>
    
    <td align="left">
      <em>
        "Meine API braucht niemals CSRF-Schutz"
      </em>
    </td>
    
    <td align="left">
      <em>
        "CORS schützt meinen Server vor Hacker-Angriffen"
      </em>
    </td>
    
    <td align="left">
      <em>
        "CSP ist optional, Escaping im Template reicht"
      </em>
    </td>
  </tr>
</tbody>
</table>

---

## 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:

```python
# 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:

```bash
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](/loesungen/cloud-sicherheit-beratung/) und maßgeschneiderte [Enterprise-Software-Entwicklung](/leistungen/software-realisierung/).

---

## 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.

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
