Sicherheitsauswirkungen von Cross-Origin Resource Sharing (CORS) in Node.js
Victor Ikechukwu
13. September 2023
0 Min. LesezeitIn modernen Webanwendungen ermöglicht Cross-Origin Resource Sharing (CORS) eine sichere Kommunikation zwischen Anwendungen, die auf unterschiedlichen Origins gehostet werden. Entwickler nutzen CORS, um innerhalb ihrer eigenen Anwendungen auf die Dienste anderer Anwendungen zuzugreifen. So müssen Funktionen nicht von Grund auf neu entwickelt werden. Das beschleunigt die Entwicklungszeit und verbessert die Developer Experience.
So hilfreich CORS auch ist: Eine fehlerhafte Implementierung kann Ihre Node.js-Anwendungen Sicherheitsrisiken wie Datenschutzverletzungen und unbefugtem Zugriff durch Websites von Drittanbietern aussetzen. Fehlkonfigurationen können dazu führen, dass sensible Daten für nicht vorgesehene Origins offengelegt werden oder bösartige Websites den Schutz durch die Same-Origin Policy (SOP) umgehen.
Wenn Sie diese Schwachstellen verstehen und Best Practices für eine sichere Implementierung von CORS befolgen, können Sie diese Risiken minimieren und zugleich die Funktionalität Ihrer Anwendung erhalten.
In diesem Artikel erklären wir zunächst, was CORS ist und wofür es eingesetzt wird. Anschließend implementieren wir CORS anhand eines Codebeispiels in einer Node.js-Anwendung. Nachdem wir die potenziellen Sicherheitsrisiken beleuchtet haben, sehen wir uns Best Practices für die Verwendung von CORS an und testen die Sicherheit unseres Beispiels. Für die Umsetzung benötigen Sie lediglich etwas Erfahrung mit JavaScript und Node.js.
CORS und seine Anwendungsfälle verstehen
Webbrowser verwenden einen Sicherheitsmechanismus namens Same-Origin Policy (SOP), um zu regeln, wie Webanwendungen miteinander interagieren. Die SOP verhindert, dass Anwendungen, die unter einer Origin gehostet werden, Ressourcen einer Anwendung von einer anderen Origin lesen.
Dieser Mechanismus verhindert, dass bösartige Websites die Daten anderer Websites lesen, kann aber auch legitime Anwendungsfälle einschränken. Was, wenn Sie Wetterdaten in Ihre Anwendung einbinden oder ein YouTube-Video auf einer Webseite einbetten möchten? Diese öffentlichen Ressourcen sollten für alle lesbar sein, doch die SOP blockiert sie.
CORS ermöglicht es Webanwendungen, die Einschränkungen der SOP zu umgehen, mit verschiedenen Webdiensten zu kommunizieren und Cross-Origin-Anfragen zu senden. Anwendungen können die HTTP-Methode OPTIONS verwenden, um Preflight-Anfragen an die Ressource der anderen Origin zu senden. Anhand dieser Preflight-Anfragen ermitteln Webbrowser, ob der Server der anderen Origin solche Anfragen zulässt. Je nach Ergebnis ignoriert der Browser die SOP oder setzt sie durch.
Typische Anwendungsfälle für CORS sind das Laden von Ressourcen aus Content Delivery Networks (CDNs), API-Anfragen über mehrere Domains hinweg und die Integration von Drittanbietern.
Eine fehlerhafte Implementierung von CORS in Ihrer Anwendung birgt jedoch Sicherheitsrisiken. Ihre Anwendung kann dadurch anfällig für Cross-Site Request Forgery (CSRF) werden. Dabei werden Nutzer dazu verleitet, unerwünschte Aktionen in der Anwendung auszuführen. Außerdem können zu großzügige Konfigurationen unbefugten Zugriff auf Nutzerdaten und sensible Informationen zwischen Origins ermöglichen. Das kann zu Datenschutzverletzungen führen oder Schwachstellen offenlegen, die Angreifer ausnutzen können.
Vielleicht sind Sie versucht, den Platzhalter alle zulassen, dargestellt durch ein Sternchen (*), als Wert für den HTTP-Header Access-Control-Allow-Origin zu verwenden. Diese CORS-Konfiguration erlaubt jeder Origin die Interaktion mit Ihrer Anwendung und öffnet damit potenziellen Schwachstellen Tür und Tor. Wählen Sie stattdessen spezifische, restriktive Konfigurationen. Für dynamische Einstellungen zulässiger Origins bieten sich Umgebungsvariablen als sicherere Alternative an.
CORS sicher in einer Node.js-Anwendung implementieren
In diesem Abschnitt zeigen wir Ihnen, wie Sie CORS sicher in einer Node.js-Anwendung implementieren. Als Beispiel verwenden wir eine einfache Node.js-Anwendung mit Express.js als Web-Framework. Sie dient als API für eine hypothetische Online-Buchhandlung.
Die API verfügt über mehrere Endpunkte, um Bücher abzurufen (fetch), hinzuzufügen (add), zu aktualisieren (update) und zu löschen (delete). In diesem Beispiel implementieren wir jedoch nur das Abrufen von Büchern. Der Einfachheit halber greift die API auf ein sampleBooksData-Objekt als Datenspeicher zu.
Voraussetzungen
Für dieses Tutorial benötigen Sie Folgendes:
Erfahrung mit JavaScript
Node.js (Version 18.16.1 wird empfohlen)
Einen modernen Webbrowser
Node.js-Anwendung erstellen
Erstellen Sie zunächst ein neues Verzeichnis für die Anwendung. Führen Sie dann im neuen Verzeichnis den folgenden Befehl aus, um eine neue Node.js-App zu initialisieren:
Führen Sie anschließend den folgenden Befehl aus, um die Abhängigkeiten für dieses Projekt zu installieren:
Erstellen Sie zum Schluss eine JavaScript-Datei mit dem Namen index.js. Fügen Sie den folgenden Code ein:
Express.js stellt Middleware-Funktionen bereit, um Anfragen und Antworten innerhalb der App zu verarbeiten. Diese Funktionen können eingehende Anfragen oder ausgehende Antworten abfangen und ändern. So lassen sich beispielsweise Protokollierung, Authentifizierung oder – wie in unserem Fall – die CORS-Konfiguration umsetzen. Im obigen Beispiel wird das CORS-Modul mit const cors = require("cors"); importiert. Es wird mit folgendem Code als Middleware-Funktion auf die Route /books angewendet:
Bei der aktuellen Implementierung der cors-Middleware auf der Route /books ist jedoch nicht ausdrücklich festgelegt, welche Origins eine GET-Anfrage senden dürfen. Daher können alle Origins Anfragen an diesen Pfad senden. Aus Sicherheitsgründen ist das keine gute Idee. Für Ihre Produktionsumgebung können Sie jedoch restriktivere Regeln konfigurieren.
CORS konfigurieren
Mit vier verschiedenen Konfigurationen können Sie CORS mithilfe der cors-Middleware sicherer implementieren.
CORS für bestimmte Origins aktivieren
Mit der Option origin in den CORS-Einstellungen legen Sie zulässige Origins fest. Diese Einstellung erhöht die Sicherheit, indem sie den Zugriff auf vertrauenswürdige Quellen beschränkt und unbefugte Cross-Origin-Anfragen verhindert. Das folgende Beispiel lässt nur Anfragen von `https://example.com` zu:
Zulässige HTTP-Methoden konfigurieren
Mit der Option methods können Sie auch zulässige Methoden festlegen. So schränken Sie potenzielle Angriffsvektoren ein, indem Sie nur notwendige Aktionen an Ihren API-Endpunkten erlauben. Das folgende Beispiel lässt nur die Aktionen GET und POST zu:
Benutzerdefinierte Header und freigegebene Header festlegen
Eine weitere Möglichkeit besteht darin, den CORS-Header Access-Control-Allow-Headers mit der Option allowedHeaders und den Header Access-Control-Expose-Headers mit der Option exposedHeaders zu konfigurieren. So kann die Anwendung sensible Daten ordnungsgemäß verarbeiten und zugleich eine flexible Kommunikation zwischen Client- und Serverkomponenten gewährleisten. Das folgende Beispiel lässt nur die Header Content-Type und Authorization zu und gibt ausschließlich X-Custom-Header frei:
Preflight-Anfragen und Caching konfigurieren
Aktivieren Sie abschließend das Caching von Preflight-Anfragen (OPTIONS), indem Sie die Cache-Dauer über die Einstellung maxAge festlegen. So kann der Client die Informationen zur CORS-Richtlinie des Servers für einen bestimmten Zeitraum zwischenspeichern. Bei nachfolgenden Anfragen können Clients auf die zwischengespeicherten CORS-Richtliniendaten zurückgreifen, ohne sie erneut vom Server abzurufen.
Ein geeigneter Wert für maxAge verkürzt die Antwortzeit und reduziert den Netzwerkaufwand. Das optimiert die Leistung und stellt zugleich sicher, dass die CORS-Richtlinien aktuell bleiben. Im folgenden Beispiel wird maxAge auf 86400 Sekunden (24 Stunden) gesetzt:
Nachdem wir die Optionen konfiguriert haben, können wir unseren Code als Middleware für alle Routen verwenden, auf denen CORS aktiviert werden muss:
CORS trägt zwar zur Sicherheit der API bei, ist aber dennoch eine Abhängigkeit eines Drittanbieters. Wir müssen sicherstellen, dass diese und alle anderen Abhängigkeiten, die wir in das Projekt aufnehmen, sicher sind und keine bekannten Schwachstellen aufweisen. Snyk Open Source hilft beispielsweise dabei, Pakete während der Entwicklung oder in CI/CD-Pipelines (Continuous Integration/Continuous Delivery) auf Sicherheitsprobleme zu überprüfen.
Sicherheitsauswirkungen von CORS und Best Practices
Wenn wir CORS nicht korrekt konfigurieren, riskieren wir die zuvor genannten Sicherheitslücken. Konkret könnten wir sensible Daten für nicht vorgesehene Origins offenlegen, bösartigen Websites unbefugte Aktionen ermöglichen (CSRF-Angriffe) und Angreifern sogar erlauben, Schutzmaßnahmen der SOP mithilfe von Techniken wie Cross-Site Scripting (XSS) zu umgehen.
Um solche Szenarien zu vermeiden, sollten Sie bei der Konfiguration von CORS immer Best Practices befolgen. Sie können außerdem weitere Sicherheitsmaßnahmen ergreifen, etwa Header außerhalb von CORS implementieren. Darauf gehen wir später in diesem Abschnitt ein.
Best Practices
Best Practices wie das Einschränken zulässiger Origins, die Verwendung sicherer Cookies und Tokens sowie die Begrenzung freigegebener Header sind unerlässlich, um Ihre Anwendungen und Nutzer zu schützen. Im Folgenden zeigen wir Ihnen anhand von Codebeispielen, wie Sie dabei vorgehen.
Zulässige Origins auf eine Positivliste beschränken
Vermeiden Sie den Platzhalter für alle Origins (*) im Objekt corsOptions und geben Sie stattdessen Origins in einer Positivliste an:
Sichere Cookies und Tokens zur Authentifizierung verwenden
Verwenden Sie das HTTPS-Schema, damit Ihre Anwendung Cookies und Tokens sicher überträgt. Nutzen Sie außerdem vertrauenswürdige Authentifizierungsbibliotheken wie Passport.js oder Lösungen mit JSON Web Token (JWT):
Im Code ermöglicht die Einstellung credentials to true, dass Cross-Origin-Anfragen Anmeldedaten enthalten.
Freigegebene Header und HTTP-Methoden einschränken
Verwenden Sie die Option exposedHeaders, um nur erforderliche Header anzugeben. Schränken Sie außerdem mit der Option methods in Ihrer Konfiguration ein, für welche Methoden CORS aktiviert wird:
Sicherheits-Header außerhalb von CORS implementieren
Sie können außerhalb von CORS zusätzliche Sicherheits-Header implementieren, um Ihre Anwendung weiter abzusichern. HTTP-Sicherheits-Header sind HTTP-Header, die Sicherheitsaspekte der HTTP-Kommunikation zwischen Client und Server festlegen.
Helmet.js stellt eine Reihe von Sicherheits-Headern mit sinnvollen Standardeinstellungen bereit. Damit die von der CORS-Konfiguration festgelegte Funktionalität aktiviert wird, ist jedoch eine entsprechende Content Security Policy (CSP)-Konfiguration erforderlich. Führen Sie zur Einrichtung die folgenden Schritte aus.
Führen Sie zunächst den folgenden Befehl in der Kommandozeile Ihres Node.js-Anwendungsverzeichnisses aus, um Helmet zu installieren:
Importieren Sie anschließend das Paket mit dem folgenden Code in Ihre Anwendung:
Konfigurieren Sie dann die CSP wie unten gezeigt passend zu Ihren CORS-Einstellungen:
Überprüfen Sie abschließend Ihre Arbeit. Gerade wenn Ihre Anwendung wächst, kann leicht eine Einstellung übersehen oder ein Tippfehler gemacht werden, der ihre Sicherheit beeinträchtigt. Snyk Code und die Entwickler-Tool-Erweiterungen von Snyk, etwa die Erweiterung für Visual Studio Code, erkennen fehlende oder falsch konfigurierte Sicherheits-Header in Ihrer Codebasis. Wenn Sie diese Tools von Drittanbietern einsetzen, um solche Sicherheitsprobleme während der Entwicklung proaktiv zu beheben, können Sie Ihre Node.js-Anwendung sicher halten.
CORS-Implementierungen und ihre Sicherheit testen
Testen Sie Ihre CORS-Implementierung und deren Sicherheit, um sicherzustellen, dass Ihre Anwendung vor potenziellen Bedrohungen geschützt ist. So lassen sich mögliche Schwachstellen und Fehlkonfigurationen erkennen. Tests bestätigen außerdem, dass die CORS-Regeln wie beabsichtigt funktionieren und die Anwendung keinen Sicherheitsrisiken wie Datenschutzverletzungen oder unbefugtem Zugriff durch Websites von Drittanbietern aussetzen.
Es gibt mehrere Möglichkeiten, CORS-Implementierungen und ihre Sicherheit zu testen. Im Folgenden stellen wir einige gängige Methoden vor.
Browser-Entwicklertools
Moderne Webbrowser bieten Entwicklertools, mit denen Sie Webanwendungen überprüfen und debuggen können. Testen Sie CORS mithilfe dieser Tools, indem Sie Netzwerkanfragen und -antworten untersuchen. Simulieren Sie Cross-Origin-Anfragen, um zu überprüfen, ob die CORS-Regeln sie wie vorgesehen blockieren oder zulassen.
Später führen wir diese Methode weiter aus und wenden sie auf die zuvor erstellte Node.js-Beispielanwendung an.
Postman
Mit dem beliebten API-Entwicklungs- und Testtool Postman können Sie CORS testen. Damit können Sie HTTP-Anfragen erstellen und benutzerdefinierte Header festlegen, um CORS-Konfigurationen zu testen. Postman kann außerdem automatisch Preflight-Anfragen generieren, um das Caching von Preflight-Anfragen zu testen. Mit den Skriptfunktionen von Postman können Sie auch Testszenarien automatisieren.
Benutzerdefinierte Skripte
Sie können benutzerdefinierte Skripte erstellen, um CORS-Konfigurationen zu testen. Verwenden Sie beispielsweise eine Skriptsprache wie Python oder JavaScript, um HTTP-Anfragen zu senden und zu prüfen, ob die Antworten CORS-Header enthalten. Sie können auch Cross-Origin-Anfragen simulieren und überprüfen, ob die CORS-Regeln diese Anfragen wie vorgesehen blockieren oder zulassen.
So testen Sie die CORS-Konfiguration mit den Entwickler-Tools des Browsers
Mit den Entwickler-Tools des Browsers können Sie die CORS-Konfigurationen in unserer Node.js-Beispielanwendung testen. Führen Sie die folgenden Schritte aus.
Starten Sie zunächst die Node.js-Anwendung. Führen Sie in der Kommandozeile des Anwendungsverzeichnisses den folgenden Befehl aus:
Rufen Sie anschließend in einem Browser Ihrer Wahl die Google-Startseite auf.

Öffnen Sie dann die Entwicklerkonsole. Verwenden Sie in einem Chromium-basierten Browser den Befehl Option+⌘+J (unter macOS) oder Shift+CTRL+ J (unter Windows/Linux). Alternativ können Sie den entsprechenden Befehl für den Browser Ihrer Wahl verwenden.
Fügen Sie den folgenden Code ein und drücken Sie dann Return/Enter:
Auf Grundlage der aktuellen CORS-Konfiguration der Beispielanwendung erhalten Sie wahrscheinlich Fehlermeldungen, die darauf hinweisen, dass die CORS-Richtlinie den Zugriff des Ursprungs (Google) auf die Ressource /books auf Ihrem Server blockiert hat und ein interner Serverfehler aufgetreten ist.

Der Fehler wegen des blockierten Zugriffs tritt auf, weil der Ursprung https://www.google.com nicht zu den Ursprüngen gehört, die die SOP umgehen dürfen. Die Einstellungen in der Option `origin` des Objekts corsOptions, das wir an die cors-Middleware übergeben, erlauben diesem Ursprung nicht, eine Antwort vom Server zu erhalten. Beachten Sie, dass die Darstellung und die Fehlermeldung je nach Browser unterschiedlich sein können. Der Fehler weist jedoch weiterhin darauf hin, dass die Anfrage blockiert wurde.
Dieser Fehler bestätigt, dass unsere CORS-Regeln wie vorgesehen funktionieren. Die Anwendung ist von nicht autorisierten Ursprüngen aus nicht zugänglich.
Um die Anfrage von https://www.google.com zuzulassen, geben Sie diesen Ursprung in der Option origin des Objekts corsOptions an:
Wenn Sie den Server neu starten und den Fetch-Befehl in der Entwicklerkonsole erneut ausführen, sollte er wie erwartet funktionieren. Wird der Fehler weiterhin angezeigt, versuchen Sie, das Skript in einem anderen Browser auszuführen. Damit der Fetch-Befehl in Brave funktioniert, müssen Sie Shields deaktivieren. Beachten Sie, dass die aktuelle CORS-Konfiguration bei Verwendung von Safari möglicherweise fehlschlägt. Das liegt an der strikten Durchsetzung der Same-Origin-Policy (SOP) durch Safari, die Anfragen von verschiedenen Ursprüngen einschränkt.

Da wir https://www.google.com in den CORS-Einstellungen zugelassen haben, wird jetzt eine Liste mit Büchern statt einer Fehlermeldung angezeigt.
Nächste Schritte
CORS erweitert Ihre Anwendung zwar um nützliche Funktionen, doch eine fehlerhafte Konfiguration kann Ihre App Sicherheitslücken aussetzen. Angesichts dieser Risiken sollten Sie nach Möglichkeit Best Practices anwenden, um Ihre Node.js-Anwendungen vor potenziellen Bedrohungen zu schützen.
Sie können die cors-Middleware mit bestimmten Ursprüngen, HTTP-Methoden, Headern und Preflight-Anfragen konfigurieren, um eine sichere Cross-Origin-Kommunikation zu ermöglichen. Tools wie Snyk Code und die Entwickler-Tools des Browsers helfen Ihnen außerdem, Fehler und Sicherheitslücken schon während der Entwicklung proaktiv aufzuspüren. So stellen Sie sicher, dass Ihre Anwendung beim Produktivstart geschützt ist und Ihre Systeme und Nutzer sicher sind.
Nachdem Sie Ihre CORS-Einstellungen anhand dieser Best Practices konfiguriert haben, testen Sie Snyk Code, um Ihre Anwendung in Echtzeit zu prüfen und Ihre Sicherheitseinstellungen noch einmal zu überprüfen. Sie können jeden Monat 200 Tests kostenlos durchführen.
Starten Sie mit Capture the Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.



