Same-Origin-Policy
Standardmäßig dürfen Browser nur Anfragen an die gleiche Origin (Schema, Host,
Port) machen, von der die Seite stammt. Eine Webseite auf
https://app.example.com darf also
nicht einfach
https://api.beispiel.de via
fetch() aufrufen — das wäre
cross-origin. Diese Same-Origin-Policy ist der wichtigste Schutz vor
unerlaubten API-Calls aus fremden Seiten (z. B. Phishing-Seiten, die im Hintergrund
deine Banking-API ansprechen).
Wozu dient CORS?
CORS ist der gezielte Aufweichungsmechanismus: Du als API-Betreiber sagst dem Browser "Ja, diese fremde Webseite darf mich ansprechen — aber nur diese." Der Browser fragt also vorher beim Server nach, ob die Anfrage erlaubt ist, und führt sie nur aus, wenn der Server zustimmt. CORS schützt also nicht deine API — die kann jeder mit curl ansprechen — sondern es schützt deine Nutzer davor, dass eine fremde Webseite in ihrem Namen API-Calls macht.
Einfache Anfragen
Bei einer einfachen GET- oder POST-Anfrage (mit Standard-Content-Types) macht der
Browser den Request einfach und prüft den Antwort-Header
Access-Control-Allow-Origin:
Access-Control-Allow-Origin: https://app.example.com
Stimmt die Origin der aufrufenden Seite überein, darf das JavaScript die Antwort lesen. Sonst blockiert der Browser den Zugriff (die Anfrage selbst wurde aber bereits ausgeführt — wichtig für GET-Requests, die Side-Effects haben sollen, niemals!).
Preflight-Requests
Bei "nicht-einfachen" Anfragen (PUT, DELETE, Custom Headers, JSON-POSTs etc.) macht der
Browser zuerst einen OPTIONS-Request
zum Server (Preflight) und fragt: "Darf ich folgende Anfrage machen?". Erst wenn der
Server zustimmt, kommt der eigentliche Request.
Antwort des Servers auf den Preflight:
Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Max-Age: 86400
Max-Age sagt dem Browser, wie
lange er die Preflight-Antwort cachen darf — sinnvoll auf 24h setzen, damit nicht jeder
Request einen extra OPTIONS-Roundtrip kostet.
Cookies und Auth
Standardmäßig schickt der Browser bei Cross-Origin-Requests keine Cookies mit. Soll er das tun (z. B. weil deine API Session-Cookies nutzt), müssen drei Dinge stimmen:
- Im Frontend:
fetch(url, { credentials: 'include' }). - Server-Antwort:
Access-Control-Allow-Credentials: true. - Server darf nicht
Access-Control-Allow-Origin: *verwenden — die Origin muss explizit angegeben werden.
Häufige Fehler
- Allow-Origin: * auf einer API mit Auth: gefährlich, weil jede Webseite zugreifen darf. Allow-Origin sollte einer Whitelist entstammen.
- Origin spiegeln:
Access-Control-Allow-Origin: ${request.origin}ohne Validierung — erlaubt jedem Aufrufer Zugriff. Validiere gegen eine echte Whitelist. - OPTIONS nicht beantwortet: Wenn dein Server
OPTIONSignoriert oder mit 405 antwortet, schlägt der Preflight fehl und der eigentliche Request läuft nie. - CORS für CSRF-Schutz halten: CORS schützt nicht vor CSRF — ein Angreifer kann mit einem Formular trotzdem POST-Requests mit Cookies absetzen. Du brauchst CSRF-Tokens.
Konfigurationsbeispiel (Flask)
from flask_cors import CORS
CORS(app, resources={
r"/api/*": {
"origins": ["https://app.example.com"],
"methods": ["GET", "POST", "PUT", "DELETE"],
"allow_headers": ["Content-Type", "Authorization"],
"supports_credentials": True,
"max_age": 86400,
}
})