Ein umfassender Leitfaden zur Verbesserung der Frontend-Sicherheit mit CSP und CORS, um Ihre Webanwendungen vor modernen Bedrohungen zu schützen.
Frontend-Sicherheitshärtung: Content Security Policy und CORS
In der heutigen vernetzten digitalen Landschaft ist die Frontend-Sicherheit von größter Bedeutung. Webanwendungen werden zunehmend zum Ziel ausgefeilter Angriffe, was robuste Sicherheitsmaßnahmen unerlässlich macht. Zwei entscheidende Komponenten einer sicheren Frontend-Architektur sind die Content Security Policy (CSP) und Cross-Origin Resource Sharing (CORS). Dieser umfassende Leitfaden bietet einen tiefen Einblick in diese Technologien und liefert praktische Beispiele und umsetzbare Erkenntnisse, die Ihnen helfen, Ihre Webanwendungen gegen moderne Bedrohungen zu wappnen.
Was ist die Content Security Policy (CSP)?
Die Content Security Policy (CSP) ist eine zusätzliche Sicherheitsschicht, die dabei hilft, bestimmte Arten von Angriffen zu erkennen und zu entschärfen, darunter Cross-Site-Scripting- (XSS) und Dateneinschleusungsangriffe. CSP wird implementiert, indem der Webserver einen Content-Security-Policy-HTTP-Response-Header an den Browser sendet. Dieser Header definiert eine Whitelist von Quellen, aus denen der Browser Ressourcen laden darf. Indem CSP die Quellen von Inhalten einschränkt, die ein Browser laden kann, wird es für Angreifer erheblich schwieriger, bösartigen Code in Ihre Website einzuschleusen.
Wie CSP funktioniert
CSP funktioniert, indem es den Browser anweist, Ressourcen (z. B. Skripte, Stylesheets, Bilder, Schriftarten) nur aus genehmigten Quellen zu laden. Diese Quellen werden im CSP-Header mithilfe von Direktiven angegeben. Wenn ein Browser versucht, eine Ressource aus einer nicht explizit erlaubten Quelle zu laden, blockiert er die Anfrage und meldet eine Verletzung.
CSP-Direktiven: Ein umfassender Überblick
CSP-Direktiven steuern die Arten von Ressourcen, die aus bestimmten Quellen geladen werden können. Hier ist eine Aufschlüsselung einiger der wichtigsten Direktiven:
- default-src: Legt die Standardquelle für alle Inhaltstypen fest. Dies ist eine Fallback-Direktive, die zur Anwendung kommt, wenn andere, spezifischere Direktiven nicht vorhanden sind.
- script-src: Gibt die Quellen an, aus denen Skripte geladen werden können. Dies ist entscheidend zur Verhinderung von XSS-Angriffen.
- style-src: Gibt die Quellen an, aus denen Stylesheets geladen werden können.
- img-src: Gibt die Quellen an, aus denen Bilder geladen werden können.
- font-src: Gibt die Quellen an, aus denen Schriftarten geladen werden können.
- media-src: Gibt die Quellen an, aus denen Audio und Video geladen werden können.
- object-src: Gibt die Quellen an, aus denen Plugins (z. B. Flash) geladen werden können. Dies wird oft auf 'none' gesetzt, um Plugins aufgrund ihrer inhärenten Sicherheitsrisiken vollständig zu deaktivieren.
- frame-src: Gibt die Quellen an, aus denen Frames (z. B. <iframe>) geladen werden können.
- connect-src: Gibt die URLs an, mit denen der User-Agent über Skript-Schnittstellen wie XMLHttpRequest, WebSocket und EventSource eine Verbindung herstellen kann.
- base-uri: Gibt die URLs an, die im <base>-Element eines Dokuments verwendet werden können.
- form-action: Gibt die URLs an, an die Formularübermittlungen gesendet werden können.
- upgrade-insecure-requests: Weist den User-Agent an, unsichere Anfragen (HTTP) automatisch auf sichere Anfragen (HTTPS) hochzustufen.
- report-uri: Gibt eine URL an, an die der Browser Berichte über CSP-Verletzungen senden soll. Diese Direktive ist veraltet und wurde durch `report-to` ersetzt.
- report-to: Gibt den Namen einer Berichtsgruppe an, die im `Report-To`-Header definiert ist, wohin der Browser Berichte über CSP-Verletzungen senden soll.
CSP-Quelllisten-Schlüsselwörter
Innerhalb von CSP-Direktiven können Sie Quelllisten-Schlüsselwörter verwenden, um erlaubte Quellen zu definieren. Hier sind einige gebräuchliche Schlüsselwörter:
- 'self': Erlaubt Ressourcen vom selben Ursprung (Schema und Host) wie das Dokument.
- 'none': Verbietet Ressourcen aus allen Quellen.
- 'unsafe-inline': Erlaubt die Verwendung von Inline-Skripten und -Stilen (z. B. <script>-Tags und style-Attribute). Mit äußerster Vorsicht verwenden, da dies den CSP-Schutz gegen XSS erheblich schwächt.
- 'unsafe-eval': Erlaubt die Verwendung von dynamischen Code-Evaluierungsfunktionen wie
eval()undFunction(). Mit äußerster Vorsicht verwenden, da dies erhebliche Sicherheitsrisiken birgt. - 'unsafe-hashes': Erlaubt bestimmte Inline-Event-Handler oder <style>-Tags, die einem angegebenen Hash entsprechen. Erfordert Browser-Unterstützung. Mit Vorsicht verwenden.
- 'strict-dynamic': Gibt an, dass das Vertrauen, das einem im Markup vorhandenen Skript explizit durch eine Nonce oder einen Hash gegeben wird, auf alle Skripte übertragen wird, die von diesem Wurzelskript geladen werden.
- data: Erlaubt data:-URIs (z. B. inline als base64 kodierte Bilder). Mit Vorsicht verwenden.
- https:: Erlaubt das Laden von Ressourcen über HTTPS von jeder Domain.
- [hostname]: Erlaubt Ressourcen von einer bestimmten Domain (z. B. example.com). Sie können auch eine Portnummer angeben (z. B. example.com:8080).
- [scheme]://[hostname]:[port]: Eine voll qualifizierte URI, die Ressourcen vom angegebenen Schema, Host und Port erlaubt.
Praktische CSP-Beispiele
Schauen wir uns einige praktische Beispiele für CSP-Header an:
Beispiel 1: Grundlegende CSP mit 'self'
Diese Richtlinie erlaubt Ressourcen nur vom selben Ursprung:
Content-Security-Policy: default-src 'self'
Beispiel 2: Erlauben von Skripten von einer bestimmten Domain
Diese Richtlinie erlaubt Skripte von Ihrer eigenen Domain und einem vertrauenswürdigen CDN:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
Beispiel 3: Deaktivieren von Inline-Skripten und -Stilen
Diese Richtlinie verbietet Inline-Skripte und -Stile, was eine starke Verteidigung gegen XSS darstellt:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
Wichtig: Das Deaktivieren von Inline-Skripten erfordert ein Refactoring Ihres HTML, um Inline-Skripte in externe Dateien zu verschieben.
Beispiel 4: Verwendung von Nonces für Inline-Skripte
Wenn Sie Inline-Skripte verwenden müssen, nutzen Sie Nonces (kryptografisch zufällige, einmalig verwendbare Tokens), um bestimmte Inline-Skriptblöcke auf die Whitelist zu setzen. Dies ist sicherer als 'unsafe-inline'. Der Server muss für jede Anfrage eine eindeutige Nonce generieren und diese sowohl im CSP-Header als auch im <script>-Tag einfügen.
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Inline script'); </script>
Hinweis: Denken Sie daran, für jede Anfrage eine neue Nonce zu generieren. Verwenden Sie Nonces nicht wieder!
Beispiel 5: Verwendung von Hashes für Inline-Stile
Ähnlich wie Nonces können Hashes verwendet werden, um bestimmte Inline-<style>-Blöcke auf die Whitelist zu setzen. Dies geschieht durch die Erzeugung eines SHA256-, SHA384- oder SHA512-Hashes des Stil-Inhalts.
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
Hinweis: Hashes sind weniger flexibel als Nonces, da jede Änderung am Stil-Inhalt den Hash ungültig macht.
Beispiel 6: Melden von CSP-Verletzungen
Um CSP-Verletzungen zu überwachen, verwenden Sie die report-uri- oder report-to-Direktive:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
Sie müssen auch den Report-To-Header konfigurieren. Der Report-To-Header definiert eine oder mehrere Berichtsgruppen, die angeben, wo und wie Berichte gesendet werden sollen.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
Testen und Bereitstellen von CSP
Die Implementierung von CSP erfordert sorgfältige Planung und Tests. Beginnen Sie mit einer restriktiven Richtlinie und lockern Sie sie bei Bedarf schrittweise. Verwenden Sie den Content-Security-Policy-Report-Only-Header, um Ihre Richtlinie zu testen, ohne Ressourcen zu blockieren. Dieser Header meldet Verletzungen, ohne die Richtlinie durchzusetzen, sodass Sie Probleme identifizieren und beheben können, bevor Sie die Richtlinie in der Produktion einsetzen.
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
Analysieren Sie die vom Browser generierten Berichte, um Verletzungen zu identifizieren und Ihre Richtlinie entsprechend anzupassen. Sobald Sie sicher sind, dass Ihre Richtlinie korrekt funktioniert, setzen Sie sie mit dem Content-Security-Policy-Header ein.
Best Practices für CSP
- Beginnen Sie mit einer default-src: Definieren Sie immer eine
default-src, um eine Basisrichtlinie festzulegen. - Seien Sie spezifisch: Verwenden Sie spezifische Direktiven und Quelllisten-Schlüsselwörter, um den Geltungsbereich Ihrer Richtlinie zu begrenzen.
- Vermeiden Sie 'unsafe-inline' und 'unsafe-eval': Diese Schlüsselwörter schwächen CSP erheblich und sollten wann immer möglich vermieden werden.
- Verwenden Sie Nonces oder Hashes für Inline-Skripte und -Stile: Wenn Sie Inline-Skripte oder -Stile verwenden müssen, nutzen Sie Nonces oder Hashes, um bestimmte Codeblöcke auf die Whitelist zu setzen.
- Überwachen Sie CSP-Verletzungen: Verwenden Sie die
report-uri- oderreport-to-Direktive, um CSP-Verletzungen zu überwachen und Ihre Richtlinie entsprechend anzupassen. - Testen Sie gründlich: Verwenden Sie den
Content-Security-Policy-Report-Only-Header, um Ihre Richtlinie zu testen, bevor Sie sie in der Produktion einsetzen. - Iterieren und verfeinern: CSP ist keine einmalige Konfiguration. Überwachen und verfeinern Sie Ihre Richtlinie kontinuierlich, um sie an Änderungen in Ihrer Anwendung und der Bedrohungslandschaft anzupassen.
Was ist Cross-Origin Resource Sharing (CORS)?
Cross-Origin Resource Sharing (CORS) ist ein Mechanismus, der es Webseiten von einem Ursprung (Domain) ermöglicht, auf Ressourcen von einem anderen Ursprung zuzugreifen. Standardmäßig erzwingen Browser eine Same-Origin Policy, die Skripte daran hindert, Anfragen an einen anderen Ursprung als den zu stellen, von dem das Skript stammt. CORS bietet eine Möglichkeit, diese Einschränkung selektiv zu lockern, um legitime Cross-Origin-Anfragen zu ermöglichen und gleichzeitig vor bösartigen Angriffen zu schützen.
Die Same-Origin Policy verstehen
Die Same-Origin Policy ist ein fundamentaler Sicherheitsmechanismus, der verhindert, dass ein bösartiges Skript von einer Website auf sensible Daten einer anderen Website zugreift. Ein Ursprung wird durch das Schema (Protokoll), den Host (Domain) und den Port definiert. Zwei URLs haben denselben Ursprung, wenn und nur wenn sie dasselbe Schema, denselben Host und denselben Port haben.
Zum Beispiel:
https://www.example.com/app1/index.htmlundhttps://www.example.com/app2/index.htmlhaben denselben Ursprung.https://www.example.com/index.htmlundhttp://www.example.com/index.htmlhaben unterschiedliche Ursprünge (unterschiedliches Schema).https://www.example.com/index.htmlundhttps://sub.example.com/index.htmlhaben unterschiedliche Ursprünge (unterschiedlicher Host).https://www.example.com:8080/index.htmlundhttps://www.example.com:80/index.htmlhaben unterschiedliche Ursprünge (unterschiedlicher Port).
Wie CORS funktioniert
Wenn eine Webseite eine Cross-Origin-Anfrage stellt, sendet der Browser zuerst eine „Preflight“-Anfrage an den Server. Die Preflight-Anfrage verwendet die HTTP-Methode OPTIONS und enthält Header, die die HTTP-Methode und die Header angeben, die die eigentliche Anfrage verwenden wird. Der Server antwortet dann mit Headern, die angeben, ob die Cross-Origin-Anfrage erlaubt ist.
Wenn der Server die Anfrage erlaubt, fügt er den Access-Control-Allow-Origin-Header in die Antwort ein. Dieser Header gibt den oder die Ursprünge an, die auf die Ressource zugreifen dürfen. Der Browser fährt dann mit der eigentlichen Anfrage fort. Wenn der Server die Anfrage nicht erlaubt, fügt er den Access-Control-Allow-Origin-Header nicht hinzu, und der Browser blockiert die Anfrage.
CORS-Header: Ein detaillierter Blick
CORS stützt sich auf HTTP-Header zur Kommunikation zwischen Browser und Server. Hier sind die wichtigsten CORS-Header:
- Access-Control-Allow-Origin: Gibt den oder die Ursprünge an, die auf die Ressource zugreifen dürfen. Dieser Header kann einen bestimmten Ursprung (z. B.
https://www.example.com), einen Platzhalter (*) odernullenthalten. Die Verwendung von*erlaubt Anfragen von jedem Ursprung, was aus Sicherheitsgründen im Allgemeinen nicht empfohlen wird. Die Verwendung von `null` ist nur für „opake Antworten“ geeignet, z. B. wenn die Ressource über das `file://`-Protokoll oder eine data-URI abgerufen wird. - Access-Control-Allow-Methods: Gibt die HTTP-Methoden an, die für die Cross-Origin-Anfrage erlaubt sind (z. B.
GET, POST, PUT, DELETE). - Access-Control-Allow-Headers: Gibt die HTTP-Header an, die in der Cross-Origin-Anfrage erlaubt sind. Dies ist wichtig für den Umgang mit benutzerdefinierten Headern.
- Access-Control-Allow-Credentials: Gibt an, ob der Browser Anmeldeinformationen (z. B. Cookies, Autorisierungs-Header) in die Cross-Origin-Anfrage aufnehmen soll. Dieser Header muss auf
truegesetzt sein, um Anmeldeinformationen zu erlauben. - Access-Control-Expose-Headers: Gibt an, welche Header dem Client zugänglich gemacht werden können. Standardmäßig ist nur eine begrenzte Anzahl von Headern zugänglich.
- Access-Control-Max-Age: Gibt die maximale Zeit (in Sekunden) an, die der Browser die Preflight-Anfrage zwischenspeichern kann.
- Origin: Dies ist ein Anfrage-Header, der vom Browser gesendet wird, um den Ursprung der Anfrage anzugeben.
- Vary: Ein allgemeiner HTTP-Header, der jedoch für CORS wichtig ist. Wenn
Access-Control-Allow-Origindynamisch generiert wird, sollte derVary: Origin-Header in die Antwort aufgenommen werden, um Caching-Mechanismen anzuweisen, dass die Antwort je nachOrigin-Anfrage-Header variiert.
Praktische CORS-Beispiele
Schauen wir uns einige praktische Beispiele für CORS-Konfigurationen an:
Beispiel 1: Erlauben von Anfragen von einem bestimmten Ursprung
Diese Konfiguration erlaubt Anfragen nur von https://www.example.com:
Access-Control-Allow-Origin: https://www.example.com
Beispiel 2: Erlauben von Anfragen von jedem Ursprung (nicht empfohlen)
Diese Konfiguration erlaubt Anfragen von jedem Ursprung. Mit Vorsicht verwenden, da dies Sicherheitsrisiken bergen kann:
Access-Control-Allow-Origin: *
Beispiel 3: Erlauben spezifischer Methoden und Header
Diese Konfiguration erlaubt die Methoden GET, POST und PUT sowie die Header Content-Type und Authorization:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Beispiel 4: Erlauben von Anmeldeinformationen
Um Anmeldeinformationen (z. B. Cookies) zu erlauben, müssen Sie Access-Control-Allow-Credentials auf true setzen und einen bestimmten Ursprung angeben (Sie können * nicht verwenden, wenn Sie Anmeldeinformationen erlauben):
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
Sie müssen auch credentials: 'include' in Ihrer JavaScript-Fetch/XMLHttpRequest-Anfrage setzen.
fetch('https://api.example.com/data', {
credentials: 'include'
})
CORS-Preflight-Anfragen
Für bestimmte Arten von Cross-Origin-Anfragen (z. B. Anfragen mit benutzerdefinierten Headern oder anderen Methoden als GET, HEAD oder POST mit einem Content-Type von application/x-www-form-urlencoded, multipart/form-data oder text/plain) sendet der Browser eine Preflight-Anfrage mit der OPTIONS-Methode. Der Server muss auf die Preflight-Anfrage mit den entsprechenden CORS-Headern antworten, um anzuzeigen, ob die eigentliche Anfrage erlaubt ist.
Hier ist ein Beispiel für eine Preflight-Anfrage und -Antwort:
Preflight-Anfrage (OPTIONS):
OPTIONS /data HTTP/1.1
Origin: https://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
Preflight-Antwort (200 OK):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Der Access-Control-Max-Age-Header gibt an, wie lange der Browser die Preflight-Antwort zwischenspeichern kann, was die Anzahl der Preflight-Anfragen reduziert.
CORS und JSONP
JSON mit Padding (JSONP) ist eine ältere Technik zur Umgehung der Same-Origin Policy. JSONP birgt jedoch erhebliche Sicherheitsrisiken und sollte zugunsten von CORS vermieden werden. JSONP beruht auf dem Einfügen von <script>-Tags in die Seite, die beliebigen Code ausführen können. CORS bietet eine sicherere und flexiblere Möglichkeit, Cross-Origin-Anfragen zu handhaben.
Best Practices für CORS
- Vermeiden Sie die Verwendung von *: Vermeiden Sie die Verwendung des Platzhalters (*) im
Access-Control-Allow-Origin-Header, da er Anfragen von jedem Ursprung zulässt. Geben Sie stattdessen den oder die spezifischen Ursprünge an, die auf die Ressource zugreifen dürfen. - Seien Sie spezifisch bei Methoden und Headern: Geben Sie die genauen HTTP-Methoden und Header an, die in den
Access-Control-Allow-Methods- undAccess-Control-Allow-Headers-Headern erlaubt sind. - Verwenden Sie Access-Control-Allow-Credentials mit Vorsicht: Aktivieren Sie
Access-Control-Allow-Credentialsnur, wenn Sie Anmeldeinformationen (z. B. Cookies) in Cross-Origin-Anfragen zulassen müssen. Seien Sie sich der Sicherheitsauswirkungen bewusst. - Sichern Sie Ihre Preflight-Anfragen: Stellen Sie sicher, dass Ihr Server Preflight-Anfragen ordnungsgemäß behandelt und die richtigen CORS-Header zurückgibt.
- Verwenden Sie HTTPS: Verwenden Sie immer HTTPS sowohl für den Ursprung als auch für die Ressourcen, auf die Sie cross-origin zugreifen. Dies schützt vor Man-in-the-Middle-Angriffen.
- Vary: Origin: Wenn Sie den
Access-Control-Allow-Origin-Header dynamisch generieren, fügen Sie immer denVary: Origin-Header hinzu, um Caching-Probleme zu vermeiden.
CSP und CORS in der Praxis: Ein kombinierter Ansatz
Obwohl CSP und CORS beide Sicherheitsbedenken adressieren, agieren sie auf unterschiedlichen Ebenen und bieten komplementären Schutz. CSP konzentriert sich darauf, den Browser daran zu hindern, bösartige Inhalte zu laden, während CORS steuert, welche Ursprünge auf Ressourcen auf Ihrem Server zugreifen können.
Durch die Kombination von CSP und CORS können Sie eine robustere Sicherheitslage für Ihre Webanwendungen schaffen. Beispielsweise können Sie CSP verwenden, um die Quellen einzuschränken, aus denen Skripte geladen werden können, und CORS, um zu steuern, welche Ursprünge auf Ihre API-Endpunkte zugreifen können.
Beispiel: Absicherung einer API mit CSP und CORS
Angenommen, Sie haben eine API, die unter https://api.example.com gehostet wird und nur von https://www.example.com aus zugänglich sein soll. Sie können Ihren Server so konfigurieren, dass er die folgenden Header zurückgibt:
API-Antwort-Header (https://api.example.com):
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
Und Sie können Ihre Website (https://www.example.com) so konfigurieren, dass sie den folgenden CSP-Header verwendet:
Website-CSP-Header (https://www.example.com):
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
Diese CSP-Richtlinie erlaubt der Website, Skripte zu laden und sich mit der API zu verbinden, verhindert aber das Laden von Skripten oder die Verbindung zu anderen Domains.
Fazit
Content Security Policy (CSP) und Cross-Origin Resource Sharing (CORS) sind wesentliche Werkzeuge zur Härtung der Sicherheit Ihrer Frontend-Anwendungen. Durch die sorgfältige Konfiguration von CSP und CORS können Sie das Risiko von XSS-Angriffen, Dateneinschleusungsangriffen und anderen Sicherheitslücken erheblich reduzieren. Denken Sie daran, mit einer restriktiven Richtlinie zu beginnen, gründlich zu testen und Ihre Konfiguration kontinuierlich zu überwachen und zu verfeinern, um sich an Änderungen in Ihrer Anwendung und der sich entwickelnden Bedrohungslandschaft anzupassen. Indem Sie der Frontend-Sicherheit Priorität einräumen, können Sie Ihre Benutzer schützen und die Integrität Ihrer Webanwendungen in der heutigen zunehmend komplexen digitalen Welt gewährleisten.