Jedes Drittanbieter-Skript auf Ihrer Checkout-, Login- oder Admin-Seite läuft mit denselben Rechten wie der Nutzer, der die Seite geladen hat. Wird der Host kompromittiert, der dieses Skript ausliefert, erhält der Angreifer diese Rechte ebenfalls, ähnlich wie bei XSS. Die Abhilfe beginnt damit, zu wissen, welche Skripte geladen werden. Danach entfernen Sie, was sich entfernen lässt, und pinnen oder beschränken den Rest.
Wissen, was auf den sensiblen Seiten läuft
Das OWASP-Cheat-Sheet zu Third-Party-JavaScript nennt drei Risiken: Kontrollverlust über Änderungen an Ihrer Client-Anwendung, Ausführung beliebigen Codes auf Client-Systemen und Abfluss sensibler Informationen an Dritte. Zu den Beispielen zählen der Ticketmaster-Vorfall von 2018 und ClearSkys Magecart-Untersuchung zum Diebstahl von Zahlungsdaten.
Erstellen Sie das Inventar Seite für Seite und beginnen Sie mit Checkout, Login und Admin. Halten Sie für jedes Skript die URL, den fachlichen Verantwortlichen, den Zweck und den Lieferweg fest. OWASP beschreibt drei Lieferwege: Anbietercode, der direkt in die Seite kopiert wurde, ein <script src>, das auf den Anbieter zeigt, und eine indirekte Anfrage über einen Tag Manager.
Der Tag Manager ist am wenigsten sichtbar. Er kann Skripte mehrerer Anbieter ausliefern, und Mitarbeitende können über eine Weboberfläche ändern, was er zurückgibt, ohne Ihren Code anzufassen. Änderungen gehen beim nächsten Seitenaufruf live, und der Code ist meist obfuskiert.
Im HTML-Quelltext tauchen diese Skripte nicht auf. Öffnen Sie die Developer Tools, wechseln Sie in den Tab Network, durchlaufen Sie Checkout und Login und listen Sie jeden Host auf, der ein Skript ausliefert.
Erst entfernen, dann spiegeln
Fragen Sie den Verantwortlichen jedes Eintrags, ob das Skript überhaupt auf dieser Seite gebraucht wird. Für ein Marketing-Tag auf einer Login-Seite oder in einem Admin-Bereich gibt es selten eine gute Begründung.
Für Skripte, die bleiben, nennt OWASP das Spiegeln im eigenen Haus als Schutzmaßnahme. Sie hosten eine geprüfte Kopie selbst, sodass ein Dritter sie nicht verändern kann, und der Anbieter erhält weder IP-Adresse noch Referrer oder Cookies des Besuchers. Der Preis ist der Pflegeaufwand: Eine gespiegelte Kopie verpasst die Fixes des Anbieters, daher muss jemand dafür zuständig sein, sie erneut zu prüfen und zu aktualisieren.
Verwaiste Anbieter sind ein eigenes Problem. Läuft die Domain, die ein Skript hostet, aus, weil der Anbieter insolvent ist oder das Projekt aufgegeben hat, kann sie jemand neu registrieren und schädlichen Code veröffentlichen. Ein toter Anbieter im Inventar ist für sich genommen ein Befund.
Verbleibende Skripte mit Subresource Integrity pinnen
Mit Subresource Integrity (SRI) gibt die Seite den Hash vor, dem eine Datei entsprechen muss. Der Browser vergleicht den Download mit diesem Hash, bevor er ein Skript ausführt oder ein Stylesheet anwendet, und liefert bei Abweichung einen Netzwerkfehler. Der MDN-Leitfaden zu SRI nennt den Befehl zur Erzeugung:
cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A
Setzen Sie der Ausgabe sha384- voran und tragen Sie sie in das Element ein:
<script src="https://cdn.example.com/script.js"
integrity="sha384-..."
crossorigin="anonymous"></script>
Das Markup unterliegt einigen Anforderungen:
- Das Attribut
crossoriginist Pflicht. Der Browser verweigert SRI beino-cors-Anfragen, ein Tag ohne dieses Attribut schlägt daher immer fehl. - Das CDN muss einen
Access-Control-Allow-Origin-Header senden. Viele senden*. - Sie können mehrere Hashes angeben. Der Browser verwendet nur die Hashes des stärksten vorhandenen Algorithmus (SHA-256, SHA-384, SHA-512 in aufsteigender Reihenfolge) und akzeptiert die Datei, wenn einer davon passt. So können Sie bei einem Upgrade zwei Versionen zulassen. Die W3C-Spezifikation beschreibt dasselbe Verhalten.
SRI passt zu Dateien, die unverändert bleiben, bis Sie sie ändern. Ein Skript, das der Anbieter nach Belieben bearbeitet, besteht die Prüfung nach jeder Änderung nicht mehr, und ein Tag-Manager-Container ist genau so ein Skript. Beschränken Sie, wer darin veröffentlichen darf, und halten Sie ihn von Ihren sensibelsten Seiten fern.
Mit Content Security Policy einschränken
SRI legt fest, was eine bestimmte Datei enthalten muss. Eine Content Security Policy (CSP) legt fest, woher Skripte überhaupt kommen dürfen. Der MDN-Leitfaden zu CSP empfiehlt, sie im Header Content-Security-Policy bei allen Antworten auszuliefern, nicht nur beim Hauptdokument.
Ein Ausgangspunkt für eine sensible Seite listet die Hosts auf, die Sie tatsächlich nutzen:
Content-Security-Policy: script-src 'self' cdn.example.com; object-src 'none'
Sobald eine script-src- oder default-src-Direktive existiert, wird Inline-JavaScript blockiert, sofern Sie es nicht ausdrücklich erlauben. MDN rät, 'unsafe-inline' zu vermeiden, weil es den Zweck einer CSP weitgehend aushebelt. Wo Sie Inline-Skripte brauchen, verwenden Sie eine Nonce: pro Antwort generiert, unvorhersehbar und von einem Template eingefügt. Für statische Seiten empfiehlt MDN stattdessen Hashes, externe Skripte benötigen dann zusätzlich das Attribut integrity.
OWASP stellt klar, dass ein Data Layer keine Sandbox ist, weil Tag-Manager-Container eigenes JavaScript und HTML ausführen können. Beschränken Sie den Veröffentlichungszugriff und prüfen Sie Änderungen wie Anwendungscode.
Lücken finden, ohne die Site zu beschädigen
Der Header Integrity-Policy veranlasst den Browser, Skripte zu blockieren, denen das Attribut integrity fehlt oder die im no-cors-Modus geladen werden. Beginnen Sie mit der Report-Only-Variante:
Integrity-Policy-Report-Only: blocked-destinations=(script), endpoints=(integrity-endpoint)
Der Endpoint benötigt einen passenden Reporting-Endpoints-Header. Verstöße treffen als Reports vom Typ integrity-violation ein und nennen die blockierte URL. Gepinnte Skripte erscheinen nicht in den Reports, sie sind daher kein vollständiges Skript-Inventar.
Treffen keine Reports mehr ein, lässt sich das Blockieren laut MDN ohne spürbare Einschränkungen für Nutzer aktivieren. Ein Tag-Manager-Container, den Sie nicht pinnen können, erzeugt weiterhin Reports, daher bleiben Seiten, die einen solchen laden, bei Report-Only. Die Header, die Ihre Seiten senden, können Sie mit unserem HTTP-Header-Checker prüfen.
Wo Sie anfangen
- Erstellen Sie das Inventar für Checkout-, Login- und Admin-Seiten anhand des Network-Tabs und erfassen Sie für jedes Skript Verantwortlichen, Zweck und Lieferweg.
- Entfernen Sie Einträge, die niemand begründen kann, besonders auf Login- und Admin-Seiten, und markieren Sie jeden Anbieter, dessen Domain verwaist wirkt.
- Spiegeln Sie Dateien, die Sie selbst pflegen und erneut prüfen wollen. Pinnen Sie jedes Skript, das bleibt: SHA-384-Hashes erzeugen,
integrityundcrossorigin="anonymous"ergänzen und im Staging testen. - Setzen Sie
Integrity-Policy-Report-Onlyfür Skripte ein und werten Sie die Reports aus. Erzwingen SieIntegrity-Policyerst, wenn jedes Skript auf der Seite einintegrity-Attribut hat, und lassen Sie Tag-Manager-Seiten bei Report-Only. - Testen Sie eine
Content-Security-Policymitscript-srcundobject-src 'none'im Staging, da sie Inline-Skripte blockiert. Beschränken Sie, wer in Ihrem Tag Manager veröffentlichen darf. Für eine externe Prüfung kann ein Penetrationstest diese Seiten abdecken.
