Was CORS ist und warum es existiert
Browser unterliegen der Same-Origin-Policy: Skripte einer Herkunft (Origin = Schema, Host und Port) dürfen standardmäßig keine Antworten von einer anderen Herkunft lesen. Diese Regel verhindert, dass eine bösartige Seite still Daten von einer anderen Domain abgreift, bei der Sie eingeloggt sind. CORS ist der vom W3C und der WHATWG standardisierte Mechanismus, mit dem ein Server diese Regel kontrolliert lockern kann - er teilt dem Browser über spezielle Antwort-Header mit, welche fremden Herkünfte auf seine Ressourcen zugreifen dürfen (MDN Web Docs).
Der zentrale Header ist Access-Control-Allow-Origin. Steht dort eine konkrete Herkunft wie 1 erlaubt der Browser dieser - und nur dieser - Seite den Lesezugriff. Steht dort der Platzhalter *, ist der Zugriff für jede Herkunft offen. Ergänzt wird das durch Access-Control-Allow-Credentials, das festlegt, ob Cookies und Authentifizierungsdaten mitgesendet werden dürfen, sowie Access-Control-Allow-Methods und Access-Control-Allow-Headers` für erlaubte HTTP-Methoden und Header. Das Zusammenspiel dieser Header entscheidet über die Sicherheit - und genau hier entstehen die typischen Fehler.
Wichtig ist die Abgrenzung: CORS ist keine serverseitige Zugriffskontrolle. Der Mechanismus weist nur den Browser an, eine Antwort für fremdes JavaScript zu sperren oder freizugeben. Ein Angreifer, der direkt - etwa per Skript außerhalb des Browsers - auf die API zugreift, wird von CORS nicht aufgehalten. Der Schutz greift ausschließlich im Browserkontext eines Opfers, dessen eingeloggte Sitzung missbraucht werden soll. Wer CORS als Ersatz für Authentifizierung oder Autorisierung behandelt, baut sich eine Scheinsicherheit. Diese Verwechslung ist eine der häufigsten Ursachen für riskante Konfigurationen.
Preflight-Anfragen: der unsichtbare zweite Request
Nicht jede Cross-Origin-Anfrage erreicht den Server direkt. Der Browser unterscheidet zwischen einfachen Anfragen (simple requests) und solchen, die eine Preflight-Anfrage auslösen. Einfache Anfragen nutzen die Methoden GET, HEAD oder POST mit einer kleinen Menge erlaubter Header - sie gehen ohne Vorabprüfung raus. Sobald jedoch eine andere Methode wie PUT, PATCH oder DELETE oder ein eigener Header wie Authorization ins Spiel kommt, schickt der Browser zuerst eine OPTIONS-Anfrage vorweg (MDN Web Docs).
Diese Preflight-Anfrage fragt den Server: Darf die geplante Methode mit diesen Headern von dieser Herkunft kommen? Der Server antwortet mit Access-Control-Allow-Methods, Access-Control-Allow-Headers und der erlaubten Herkunft. Erst wenn die Antwort passt, sendet der Browser die eigentliche Anfrage. Für das Monitoring ist diese Zweistufigkeit zentral: Eine Fehlkonfiguration kann sich entweder in der Preflight-Antwort verstecken (etwa zu weit gefasste erlaubte Methoden) oder in der finalen Antwort (etwa eine gespiegelte Herkunft). Eine Prüfung, die nur den GET-Pfad betrachtet, übersieht die Hälfte des Bildes.
Ein praktischer Nebeneffekt der Preflight-Mechanik betrifft die Zwischenspeicherung. Der Server kann über den Access-Control-Max-Age-Header festlegen, wie lange der Browser eine Preflight-Antwort wiederverwendet, bevor er erneut nachfragt. Ist dieser Wert sehr hoch gesetzt, können veraltete oder versehentlich zu permissive Preflight-Antworten länger im Browser-Cache verbleiben - eine Korrektur auf dem Server wirkt dann nicht sofort für alle Besucher. Für die Überwachung bedeutet das: Auch der Max-Age-Wert gehört zum Bild, das eine gründliche Header-Prüfung erfasst, denn er bestimmt mit, wie schnell sich eine Änderung im realen Verhalten niederschlägt.
Die OPTIONS-Preflight-Antwort taucht in keiner normalen Seitenansicht auf und wird von einfachen Verfügbarkeitsprüfungen nicht erfasst. Sie ist nur sichtbar, wenn ein Werkzeug gezielt eine Cross-Origin-Methode mit eigenen Headern simuliert und die Antwort-Header protokolliert. Genau deshalb bleiben zu permissive Preflight-Antworten häufig unentdeckt, bis sie aktiv getestet werden.
Die häufigsten CORS-Fehlkonfigurationen
Die meisten gefährlichen CORS-Konfigurationen entstehen aus dem Versuch, einen Browser-Fehler schnell wegzubekommen. Entwickler sehen eine blockierte Anfrage, lesen die Herkunft aus dem Origin-Header und spiegeln sie ungeprüft zurück - der Fehler verschwindet, die Lücke bleibt (PortSwigger Web Security Academy). Die folgende Übersicht ordnet die typischen Muster nach ihrem Risiko ein.
| Konfiguration | Verhalten | Risiko |
|---|---|---|
| Origin ungeprüft gespiegelt | Server kopiert jeden Origin-Header in Allow-Origin | Hoch - jede Seite liest credentialisierte Antworten |
| Wildcard mit Credentials | Allow-Origin: * zusammen mit Credentials: true | Hoch - vom Standard untersagt, aber per Spiegelung umgangen |
| null-Origin vertraut | Allow-Origin: null wird akzeptiert | Mittel bis hoch - per Sandbox-iFrame ausnutzbar |
| Zu breites Suffix-Matching | kunde.de matcht auch böse-kunde.de | Hoch - Angreifer registriert passende Domain |
| Alle Subdomains vertraut | jede *.kunde.de gilt als erlaubt | Mittel - eine übernommene Subdomain genügt |
| Wildcard ohne Credentials | Allow-Origin: * für rein öffentliche Daten | Gering - in der Regel akzeptabel |
Besonders heimtückisch ist die ungeprüft gespiegelte Herkunft in Kombination mit Access-Control-Allow-Credentials: true. Diese Kombination ist funktional gleichbedeutend mit einer Wildcard für credentialisierte Anfragen: Jede Website im Internet kann dann mit den Cookies des Opfers Anfragen stellen und die Antworten auslesen (PortSwigger Web Security Academy). Der CORS-Standard verbietet zwar die wörtliche Kombination * plus Credentials - die Spiegelung des konkreten Origin umgeht dieses Verbot jedoch vollständig. Ergänzend fehlt in solchen Fällen oft der Vary: Origin-Header, was zu fehlerhaftem Caching der freigebenden Antwort führen kann.
Eine weitere, oft unterschätzte Quelle von Fehlern ist das Abgleichen der Herkunft per Zeichenketten-Vergleich statt per exakter Prüfung. Wird etwa nur geprüft, ob der Origin die eigene Domain als Bestandteil enthält, gilt unter Umständen auch 1 als zulässig - der vertraute Name steht darin, die tatsächliche Herkunft ist jedoch eine fremde. Ähnlich riskant ist ein zu großzügiges Suffix-Matching, bei dem ein Präfix wie böse-kunde.de` fälschlich als zur eigenen Marke gehörig durchgeht. Solche Logikfehler entstehen meist in selbst geschriebenen Origin-Prüfungen und sind von außen nur durch gezielte Probe-Anfragen mit manipulierten Herkünften sichtbar zu machen.
Das ungeprüfte Zurückspiegeln des Origin-Headers ist die mit Abstand riskanteste verbreitete Praxis - es entsteht meist als vermeintlicher Bugfix gegen Browser-Fehlermeldungen. Der korrekte Weg ist stets eine explizite Allowlist vertrauenswürdiger Herkünfte, nicht eine dynamische Spiegelung. Nach jedem Deploy, der die API-Schicht berührt, sollte dieser Punkt zuerst geprüft werden.
Welches Risiko eine CORS-Lücke real bedeutet
Eine ausnutzbare CORS-Fehlkonfiguration erlaubt einem Angreifer, im Namen eines eingeloggten Opfers Daten von Ihrer API zu lesen. Besucht das Opfer eine präparierte Seite, kann deren JavaScript eine credentialisierte Anfrage an Ihre Anwendung senden und - dank der zu lockeren Header - die Antwort auslesen: Profildaten, Tokens, interne Informationen. CORS-Fehler gehören damit zur Kategorie Security Misconfiguration, die in den OWASP Top 10 als eigenes Risiko geführt wird (OWASP). Stehen verändernde Methoden offen, kann über denselben Weg auch in die Anwendung geschrieben werden.
Die finanziellen Folgen eines daraus resultierenden Datenabflusses sind erheblich. Die durchschnittlichen Kosten einer Datenpanne lagen 2024 weltweit bei 4,88 Millionen US-Dollar - der höchste Wert seit Beginn der Erhebung und ein Anstieg von 10 Prozent gegenüber dem Vorjahr (IBM Cost of a Data Breach 2024). Gleichzeitig entfielen laut dem Verizon-Lagebericht 77 Prozent der einfachen Angriffe auf Web-Anwendungen auf gestohlene Zugangsdaten (Verizon DBIR 2024) - und genau solche Zugangsdaten und Sitzungstokens sind es, die über eine CORS-Lücke ausgelesen werden können. Eine fehlkonfigurierte CORS-Antwort verschiebt die Angriffsfläche in den Browser des Nutzers, wo klassische serverseitige Schutzmaßnahmen nicht greifen.
Ein einziger Build, der die CORS-Behandlung einer API ändert, kann unbemerkt eine vertrauliche Schnittstelle für das gesamte Web öffnen. Da die Header im normalen Seitenbetrieb unsichtbar sind, fällt das oft erst auf, wenn ein Sicherheitstest oder ein Vorfall es ans Licht bringt. Kontinuierliche Header-Überwachung verkürzt dieses Zeitfenster von Wochen auf Stunden.
Hinzu kommt die schiere Verbreitung des Problems: In der erwähnten Großuntersuchung vertrauten zehntausende Domains pauschal allen ihren Subdomains, sodass die Übernahme einer einzigen vergessenen Subdomain genügte, um die CORS-Freigabe auszunutzen (Chen et al., USENIX 2018). Dieses Muster zeigt, dass CORS-Sicherheit eng mit der Überwachung der gesamten Subdomain- und DNS-Landschaft verzahnt ist - eine übersehene oder gekaperte Subdomain wird über eine zu breite CORS-Regel direkt zum Einfallstor.
CORS-Header technisch korrekt prüfen
Eine belastbare Prüfung simuliert das Verhalten eines echten Browsers: Sie sendet eine Anfrage mit einem fremden, bewusst nicht vertrauenswürdigen Origin-Header und beobachtet, was der Server in den Antwort-Headern zurückgibt. Spiegelt er den fremden Origin? Setzt er gleichzeitig Allow-Credentials: true? Akzeptiert er ein null-Origin? Genau diese Fälle trennen eine harmlose von einer ausnutzbaren Konfiguration.
Probe-Anfrage:
Origin: 1
Antwort vor Deploy v204 (Soll):
Access-Control-Allow-Origin: 2
Access-Control-Allow-Credentials: true
Vary: Origin
=> fremder Origin abgelehnt ok
Antwort nach Deploy v204 (beobachtet):
+ Access-Control-Allow-Origin: 3
+ Access-Control-Allow-Credentials: true
- Vary: Origin (fehlt)
=> fremder Origin gespiegelt VERSTOSS
=> Drift erkannt: Endpunkt spiegelt jeden OriginEntscheidend ist, dass die Prüfung mehrere Endpunkte und beide Anfrage-Stufen abdeckt - die Preflight-Antwort ebenso wie die finale Antwort. Das XICTRAQ Security-Monitoring wertet die sicherheitsrelevanten Antwort-Header einer Seite regelmäßig aus, klassifiziert die CORS-Konfiguration und gleicht den aktuellen Zustand gegen eine zuletzt bekannte saubere Baseline ab. So wird eine neue, zu permissive Freigabe als Abweichung sichtbar, statt im Rauschen unterzugehen.
- Fremder Probe-Origin - die Prüfung sendet einen bewusst nicht vertrauenswürdigen Origin und beobachtet die Reaktion des Servers
- Spiegelungs-Erkennung - ob der fremde Origin ungeprüft in Allow-Origin zurückkommt, wird explizit geprüft
- Credentials-Kopplung - die riskante Kombination aus gespiegeltem Origin und Allow-Credentials: true wird hervorgehoben
- null-Origin-Test - es wird geprüft, ob ein null-Origin fälschlich als vertrauenswürdig gilt
- Baseline-Diff - der aktuelle Header-Satz wird gegen den letzten freigegebenen Stand verglichen, sodass nur echte Änderungen alarmieren
Eine CORS-Konfiguration sauber aufsetzen
Eine robuste CORS-Konfiguration folgt einigen wenigen, klaren Prinzipien. An erster Stelle steht das Prinzip der minimalen Freigabe: Erlaubt wird nur, was tatsächlich gebraucht wird - eine konkrete, kurze Liste vertrauenswürdiger Herkünfte statt eines Platzhalters. Jede Herkunft auf dieser Liste sollte einen nachvollziehbaren Grund haben. Wächst die Liste über die Zeit, lohnt sich eine regelmäßige Durchsicht, ob jeder Eintrag noch benötigt wird, denn jede zusätzliche erlaubte Herkunft vergrößert die Angriffsfläche.
- Exakte Allowlist statt Spiegelung - die erlaubten Herkünfte werden gegen eine feste Liste geprüft und nur bei exakter Übereinstimmung zurückgegeben, statt den eingehenden Origin ungeprüft zu kopieren
- Credentials sparsam einsetzen -
Access-Control-Allow-Credentials: truewird nur dort gesetzt, wo authentifizierte Cross-Origin-Zugriffe wirklich nötig sind, und stets mit einer exakten Herkunft kombiniert - null-Origin ablehnen - der Wert
nullwird nicht als vertrauenswürdig behandelt, da er sich über Sandbox-Konstrukte erzeugen lässt - Vary: Origin setzen - sobald die Antwort je nach Herkunft variiert, signalisiert dieser Header Caches, die Herkunft in den Cache-Schlüssel einzubeziehen
- Preflight eng halten - erlaubte Methoden und Header werden auf das beschränkt, was die Anwendung tatsächlich nutzt
Diese Grundsätze sind kein einmaliges Projekt, sondern ein Zustand, der nach jedem Eingriff in die API-Schicht erneut bestätigt werden sollte. Genau hier setzt das kontinuierliche Monitoring an: Es prüft nicht, ob die Konfiguration einmal korrekt war, sondern ob sie es geblieben ist. Eine Konfiguration, die heute sauber ist, kann nach dem nächsten Framework-Update oder der nächsten Middleware-Änderung bereits abweichen - und ohne laufende Beobachtung bleibt diese Abweichung im Verborgenen.
Was XICTRAQ rund um CORS und Header überwacht
CORS ist ein Baustein eines breiteren Security-Header-Bildes. Eine isolierte Prüfung greift zu kurz - erst im Zusammenspiel mit den übrigen Schutz-Headern und der laufenden Verfügbarkeitsprüfung entsteht ein belastbares Bild. XICTRAQ bündelt diese Aspekte in einer kontinuierlichen Überwachung.
Klassifizierung von Allow-Origin, Allow-Credentials und erlaubten Methoden inklusive Erkennung gespiegelter und zu breiter Freigaben.
Die OPTIONS-Antwort wird mitgeprüft, sodass zu permissive Allow-Methods und Allow-Headers nicht übersehen werden.
Jede Änderung der CORS-Header gegenüber dem freigegebenen Stand wird als Abweichung erkannt - ideal nach jedem Deploy.
Eine neue, zu permissive Freigabe löst eine Benachrichtigung per E-Mail, Slack, Discord oder Telegram aus.
Diese CORS-Prüfung fügt sich in ein größeres Security-Header-Monitoring ein, das auch Transport- und Browser-Schutzmechanismen abdeckt. So gehört zur belastbaren Absicherung etwa die Härtung der TLS-Cipher-Suites auf Transportebene ebenso wie die Überwachung der übrigen Sicherheits-Header. CORS allein schützt nicht - es ist ein Glied in einer Kette, deren schwächstes Element das Gesamtniveau bestimmt.
Wie bei anderen unsichtbaren Frontend-Problemen liegt der Wert in der Früherkennung: So wie das Monitoring von JavaScript-Fehlern im Frontend Probleme sichtbar macht, die im normalen Seitenbetrieb verborgen bleiben, macht die Header-Überwachung eine still entstandene CORS-Lücke zu einem alarmierbaren Signal. In beiden Fällen gilt: Was nicht gemessen wird, fällt erst auf, wenn es zu spät ist.
Der praktische Nutzen liegt im Zeitfaktor. Ohne Überwachung wird eine CORS-Fehlkonfiguration erfahrungsgemäß erst bei einem Penetrationstest, einer Meldung oder einem Vorfall entdeckt - oft Wochen oder Monate nach dem auslösenden Deploy. Mit kontinuierlicher Prüfung wird dieselbe Abweichung typischerweise innerhalb von Stunden sichtbar, meist bevor sie aktiv ausgenutzt werden konnte. Diese Verkürzung des Zeitfensters ist der eigentliche Schutz, den ein laufendes Monitoring bietet.
Hilfreich ist es, die CORS-Pflege organisatorisch zu verankern. Wer eine kurze, gepflegte Liste der tatsächlich benötigten fremden Herkünfte führt, kann jede neue Freigabe bewusst gegen diese Liste abwägen, statt sie reaktiv im Build hinzuzufügen. Wird im Zuge eines geplanten Releases eine neue, korrekt eingeschränkte Herkunft ergänzt, sollte die Baseline anschließend bewusst neu freigegeben werden - so alarmiert das Monitoring nur noch bei echten, ungewollten Abweichungen und nicht bei jeder geplanten Änderung. Diese Trennung zwischen beabsichtigter und unbeabsichtigter Änderung ist der Kern eines belastbaren Header-Monitorings.
Dieser Artikel basiert auf Daten und Standards von: Chen, Jiang, Duan, Wan, Chen, Paxson und Yang - We Still Don't Have Secure Cross-Domain Requests: an Empirical Study of CORS (27. USENIX Security Symposium 2018, 27,5 % unsichere CORS-konfigurierte Domains, pauschales Subdomain-Vertrauen), MDN Web Docs (CORS-Grundlagen, Preflight-Anfragen, Access-Control-Header, einfache Anfragen), W3C / WHATWG Fetch Standard (CORS-Protokoll), OWASP (Security Misconfiguration in den OWASP Top 10), PortSwigger Web Security Academy (Origin-Reflection, Credentials-Kombination, null-Origin), IBM Cost of a Data Breach 2024 (durchschnittliche Kosten 4,88 Mio. USD), Verizon Data Breach Investigations Report 2024 (77 Prozent gestohlene Zugangsdaten bei einfachen Web-App-Angriffen).