Was ist CORS und wie funktioniert es?
Autor: Redaktion Domeny.ForSale Veröffentlicht
Kurz erklärt: CORS (Cross-Origin Resource Sharing) ist ein Mechanismus, mit dem ein Server dem Browser erlauben kann, eine Antwort für ein Skript anderer Herkunft zugänglich zu machen. Die Erlaubnis wird über die Antwort-Header des Servers erteilt; der Browser setzt diese Vorgaben durch. Ein CORS-Fehler bedeutet daher meist, dass die Berechtigung zum Lesen der Antwort fehlt – nicht unbedingt, dass keine Verbindung zum Server besteht.
Warum der Browser den Zugriff zwischen verschiedenen Adressen einschränkt
Browser verwenden die Same-Origin Policy, also das Prinzip des gleichen Ursprungs. Sie schränkt ein, welche Daten ein Skript von einem anderen Ursprung lesen darf. Dadurch kann eine in einem Tab geöffnete Website nicht ungehindert private Daten aus anderen Diensten abrufen und lesen, bei denen der Nutzer angemeldet ist.
Der Ursprung (Origin) besteht aus drei Elementen: Protokoll, Hostname und Port. Sobald sich eines davon unterscheidet, handelt es sich um einen anderen Ursprung. Der Pfad hinter dem Hostnamen spielt dabei keine Rolle.
Für die Seite https://shop.example ergibt sich folgender Vergleich:
| Zieladresse | Gleicher Ursprung? | Grund |
|---|---|---|
https://shop.example/produkte | Ja | Nur der Pfad ändert sich |
https://api.shop.example | Nein | Anderer Hostname |
http://shop.example | Nein | Anderes Protokoll |
https://sklep.example:8443 | Nein | Anderer Port als der Standardport 443 |
Mit CORS kann der Server diese Regel gezielt lockern. CORS ist keine HTTP-Methode wie GET oder POST, sondern ein auf HTTP-Headern beruhender Mechanismus.
Einfaches Beispiel: Ein Shop ruft eine Produktliste ab
Angenommen, die Website läuft unter https://shop.example und die API, also die Schnittstelle zum Bereitstellen der Anwendungsdaten, unter https://api.shop.example. Das Skript der Website möchte Produkte abrufen:
fetch('https://api.sklep.example/produkty')
.then(antwort => antwort.json())
.then(produkte => console.log(produkte));
Da die Adressen unterschiedliche Ursprünge haben, ergänzt der Browser die Anfrage um einen Header, der den Ursprung der Website angibt:
Origin: https://sklep.example
Der API-Server kann mit Daten und einem Header antworten, der den Zugriff erlaubt:
Access-Control-Allow-Origin: https://sklep.example
Der Browser vergleicht diesen Wert mit dem Ursprung der Website. Passt die Erlaubnis, macht er die Antwort für das Skript zugänglich. Fehlt der Header oder nennt er eine andere Adresse, kann das Skript die Antwort nicht lesen – selbst wenn der Server den Status 200 OK zurückgegeben hat.
Der Header mit der Zugriffserlaubnis muss vom API-Server stammen. Access-Control-Allow-Origin im browserseitigen Code zur Anfrage hinzuzufügen, löst das Problem nicht.
Wann der Browser zuerst OPTIONS sendet
Nicht jede Anfrage an einen anderen Ursprung wird sofort gesendet. Bei manchen führt der Browser zunächst einen Preflight durch: eine Vorabanfrage, mit der er die Erlaubnis des Servers prüft.
Das geschieht beispielsweise beim Senden einer Bestellung mit der Methode POST und dem Inhaltstyp application/json. Auch die Verwendung des Headers Authorization löst eine solche Prüfung aus. Die Vorabanfrage kann so aussehen:
OPTIONS /bestellungen HTTP/1.1
Origin: https://sklep.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Der Server sollte mit einer Erlaubnis antworten, die den Ursprung, die Methode und die benötigten Header abdeckt:
Access-Control-Allow-Origin: https://sklep.example
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Erst nach erfolgreicher Prüfung sendet der Browser die eigentliche POST-Anfrage. Auch die Antwort auf diese POST-Anfrage muss den passenden Header Access-Control-Allow-Origin enthalten.
Nicht jede POST-Anfrage erfordert einen Preflight. Entscheidend sind auch die Header und der Typ des übertragenen Inhalts; eine gewöhnliche GET-Anfrage ohne zusätzliche Header benötigt häufig keine Vorabanfrage.
Cookies und Sternchen: zwei wichtige Stolperfallen
Eine öffentliche API, deren Antworten Skripten beliebiger Herkunft zugänglich sein sollen, kann Folgendes zurückgeben:
Access-Control-Allow-Origin: *
Für Anfragen, die Cookies in einem Modus mit Berücksichtigung von Anmeldedaten mitsenden, ist das Sternchen jedoch nicht geeignet. In diesem Fall kann der Code credentials: 'include' verwenden. Der Server muss dann einen konkreten erlaubten Ursprung angeben und Folgendes zurückgeben:
Access-Control-Allow-Origin: https://sklep.example
Access-Control-Allow-Credentials: true
Die CORS-Konfiguration allein garantiert nicht, dass Cookies übertragen werden. Es gelten auch die Cookie-Regeln, darunter SameSite, sowie die Datenschutzbeschränkungen des Browsers.
Wenn der Server mehrere vertrauenswürdige Ursprünge unterstützt, sollte er den Header Origin mit einer Liste erlaubter Werte abgleichen. Jeden empfangenen Ursprung ungeprüft zusammen mit einer Erlaubnis für Anmeldedaten zurückzusenden, kann private Antworten offenlegen. Hängt die Antwort von Origin ab, muss außerdem Vary: Origin gesetzt werden, damit der Cache die verschiedenen Antwortvarianten unterscheidet.
So diagnostizieren Sie einen CORS-Fehler
Öffnen Sie in den Entwicklertools des Browsers den Netzwerk-Tab und prüfen Sie diese vier Punkte:
- Vergleichen Sie Protokoll, Host und Port der Website mit denen der API.
- Prüfen Sie, ob eine
OPTIONS-Anfrage erfolgt und ob der Server korrekt darauf antwortet. - Sehen Sie sich die Antwort-Header der eigentlichen Anfrage an, auch bei einem Serverfehler.
- Prüfen Sie, ob die Erlaubnis die verwendete Methode, die Header und gegebenenfalls die Anmeldedaten abdeckt.
Dass ein Aufruf mit curl funktioniert, beweist nicht, dass CORS korrekt konfiguriert ist: Ein solches Werkzeug setzt die Beschränkungen des Browsers nicht durch. Auch mode: 'no-cors' ermöglicht keinen Lesezugriff auf JSON. Diese Einstellung liefert eine undurchsichtige Antwort, deren Inhalt dem Skript nicht zugänglich ist.
CORS ersetzt weder die Anmeldung noch Berechtigungsprüfungen oder den Schutz vor CSRF, also dem Erzwingen unerwünschter Aktionen durch eine andere Website. Manche Anfragen können den Server erreichen, obwohl der Browser das Lesen der Antwort blockiert. Beginnen Sie die Fehlerbehebung bei der Konfiguration der API oder eines von Ihnen kontrollierten Vermittlers, statt die Sicherheitsfunktionen des Browsers abzuschalten.
Siehe auch: Was ist eine API?
