Subresource Integrity fuer externe Skripte - Der Browser prueft die Bytes
Ein einzelnes externes <script>-Tag kann beinahe unbedeutend wirken. Dennoch weist es den Browser jedes Besuchers an, Code von einem anderen Server herunterzuladen und innerhalb der Seite auszufuehren. HTTPS schuetzt den Weg zu diesem Server, aber wodurch wird geprueft, ob die zurueckgegebene Datei wirklich genau die vom Websitebetreiber erwartete Version ist?
Subresource Integrity (SRI) gibt dem Browser einen erwarteten kryptografischen Digest fuer eine Ressource vor. Stimmen die heruntergeladenen Bytes nicht damit ueberein, verwendet der Browser sie nicht. Das ist eine eng begrenzte Kontrolle und keine vollstaendige Abwehr gegen Supply-Chain-Risiken. Gerade diese Begrenzung ist jedoch nuetzlich: SRI beantwortet eine konkrete Frage, bevor ein externes Skript ausgefuehrt oder ein Stylesheet angewendet wird.
Das verborgene Vertrauen in eine externe Ressource
Betrachten wir eine Seite, die eine Bibliothek ueber ein Content Delivery Network einbindet:
<script src="https://cdn.example.com/library-4.2.1.min.js"></script>
Die Seite delegiert mehr als nur die Auslieferung einer Datei. Auf diese Weise geladenes JavaScript laeuft im Kontext der Seite. Das OWASP Third Party JavaScript Management Cheat Sheet hebt den damit verbundenen Kontrollverlust hervor: Code von Drittanbietern kann sich ausserhalb des eigenen Release-Prozesses aendern, Code auf dem Client ausfuehren und auf Informationen zugreifen, die auf der Seite verfuegbar sind.
TLS bleibt unverzichtbar. Es hilft dem Browser, mit dem vorgesehenen Server zu kommunizieren, ohne dass ein Vermittler die Antwort einfach veraendern kann. Die W3C SRI Recommendation unterscheidet jedoch einen wichtigen Punkt: Sicherer Transport authentifiziert die Verbindung, waehrend SRI den erwarteten Inhalt festlegt. Wenn sich das CDN, dessen Deployment-Prozess oder die Datei hinter einer veraenderlichen URL aendert, kann eine gueltige HTTPS-Verbindung zuverlaessig Bytes liefern, die der Websitebetreiber nicht geprueft hat.
Was der Browser tatsaechlich prueft
Ein SRI-Wert enthaelt den Namen eines Hash-Algorithmus und einen base64-codierten Digest. Die stabile W3C Recommendation spezifiziert dafuer SHA-256, SHA-384 und SHA-512. Ein typischer SHA-384-Wert hat diese Form:
sha384-aZEZqsD0hQTrQxOOiN+3hK9zrIM0coHjnIZM4RkuhmT3K0qz+sJn2b0NZNhsunyB
Der Digest ist weder Verschluesselung noch Passwort oder Beweis dafuer, wer die Datei geschrieben hat. Er ist ein kompaktes Ergebnis, das aus den exakten Bytes berechnet wird. Die Seite deklariert das erwartete Ergebnis in einem integrity-Attribut. Der Browser laedt die Ressource herunter, berechnet ihren Digest und vergleicht die Werte, bevor er das Skript ausfuehrt oder das Stylesheet anwendet. Unterscheiden sie sich, behandelt der Browser den Ladevorgang als Netzwerkfehler.
Dieses Scheitern ist beabsichtigt. SRI macht aus einer unbemerkten Inhaltsaenderung eine blockierte Ressource. Die Integritaet steigt auf Kosten der Verfuegbarkeit: Ein veraendertes Skript kann eine Funktion stoppen, ein veraendertes Stylesheet eine Seite ungestaltet lassen. Die Kontrolle ist nur dann nuetzlich, wenn die Website zugleich einen bewussten Prozess fuer Updates und Fehlerbehandlung besitzt.
Den Digest aus den tatsaechlich auszuliefernden Bytes erzeugen
Nehmen wir an, library-4.2.1.min.js ist die gepruefte Datei. Der SRI-Leitfaden von MDN dokumentiert eine OpenSSL-Pipeline zur Erzeugung eines SHA-384-Digests:
openssl dgst -sha384 -binary library-4.2.1.min.js | openssl base64 -A
Fuer eine lokale Testdatei mit console.log("SRI example"); und einem anschliessenden Zeilenumbruch wurde verifiziert, dass dieser Befehl folgendes Ergebnis erzeugt:
aZEZqsD0hQTrQxOOiN+3hK9zrIM0coHjnIZM4RkuhmT3K0qz+sJn2b0NZNhsunyB
Dem Ergebnis wird sha384- vorangestellt. Noch wichtiger ist, dass genau das Artefakt gehasht wird, das die Besucher erhalten. Wird eine Quelldatei gehasht und anschliessend von einem Build-Tool, CDN oder optimierenden Proxy minimiert oder anderweitig transformiert, entstehen andere Bytes und damit eine Abweichung. Auch eine Aenderung der Zeilenenden ist eine Aenderung der Bytes.
Auch ein Remote-Download kann gehasht werden, doch dabei ist Vorsicht geboten: Aus dem heutigen Inhalt einer URL einen Digest zu bilden, beweist nicht, dass die Datei vertrauenswuerdig ist. Zuerst sollten Version und Zweck geprueft und die Datei ueber einen vertrauenswuerdigen Release-Pfad bezogen werden. SRI kann diese Entscheidung bewahren, aber nicht selbst treffen.
Integritaetsmetadaten zu Skripten und Styles hinzufuegen
Fuer ein auf einem anderen Origin gehostetes Skript kann das Markup so aussehen:
<script
src="https://cdn.example.com/library-4.2.1.min.js"
integrity="sha384-aZEZqsD0hQTrQxOOiN+3hK9zrIM0coHjnIZM4RkuhmT3K0qz+sJn2b0NZNhsunyB"
crossorigin="anonymous"></script>
Der gleiche Mechanismus schuetzt ein externes Stylesheet:
<link
rel="stylesheet"
href="https://cdn.example.com/theme-4.2.1.min.css"
integrity="sha384-REPLACE_WITH_THE_STYLESHEET_DIGEST"
crossorigin="anonymous">
Der Platzhalter ist beabsichtigt: Ein Stylesheet benoetigt einen aus seinen eigenen Bytes berechneten Digest. Den Digest des Skripts wiederzuverwenden waere falsch.
Warum crossorigin="anonymous" wichtig ist
Bei einer Cross-Origin-Ressource setzt die SRI-Validierung eine fuer CORS zulaessige Antwort voraus. Mit crossorigin="anonymous" verwendet das Element den CORS-Modus, ohne Cross-Origin-Zugangsdaten zu senden. Der Asset-Server muss ausserdem einen passenden Access-Control-Allow-Origin-Header liefern. Erlaubt das CDN kein CORS, reicht das Hinzufuegen eines Digests nicht aus, um die Ressource erfolgreich zu laden.
Dies sollte vom tatsaechlichen Origin der Seite aus getestet werden, nicht nur durch direktes Oeffnen der Asset-URL in einem Tab. Eine direkte Anfrage mit HTTP 200 beweist nicht, dass die Cross-Origin-Anfrage und die Integritaetspruefung des Browsers erfolgreich sind.
Ein vorsichtiger Rollout- und Update-Prozess
SRI eignet sich am besten, wenn Ressourcen-URLs unveraenderliche Versionen bezeichnen. Eine URL mit der Endung 4.2.1 vermittelt einen besseren Vertrag als latest.js, doch der Name allein ist kein Beweis; der Host muss die Bytes tatsaechlich stabil halten.
Ein Ablauf fuer eine kleine Website kann ueberschaubar bleiben:
- Extern geladene Skripte und Styles inventarisieren, einschliesslich der durch Templates, Plugins, Consent-Tools und Tag Manager eingefuegten Assets.
- Abhaengigkeiten entfernen, deren Nutzen fuer das erforderliche Vertrauen zu gering ist.
- Eine feste Version waehlen und deren Release-Quelle sowie Zweck pruefen.
- Das exakte Artefakt beziehen, seinen Digest berechnen und den passenden
integrity-Wert hinzufuegen. - Die CORS-Antwort des Asset-Hosts bestaetigen und die wirkliche Seite im Browser testen.
- Den Digest in einer Testkopie voruebergehend veraendern und bestaetigen, dass der Browser die Ressource blockiert und in den Entwicklerwerkzeugen einen Integritaetsfehler meldet.
- Dokumentieren, wie Version und Digest gemeinsam aktualisiert werden, und wichtige Seiten nach Releases ueberwachen.
Der absichtliche Test mit einem falschen Digest gehoert in eine Nicht-Produktionskopie. Er prueft den Fehlerpfad, ohne zu behaupten, dass jeder Browser, Proxy oder jede Deployment-Umgebung ueber die Anforderungen des Standards hinaus identisch reagiert.
Was SRI nicht loest
Der Begriff „Integritaet“ kann umfassender klingen, als der Mechanismus tatsaechlich ist. Mehrere Grenzen sind wichtig:
- SRI macht Code nicht sicher. Eine verwundbare oder datenschutzfeindliche Datei kann perfekt zu ihrem Digest passen. SRI belegt die Uebereinstimmung mit erwarteten Bytes, nicht gutes Verhalten.
- SRI ersetzt keine Updates. Wer eine alte Bibliothek festlegt, legt auch ihre Fehler fest. Abhaengigkeitsueberwachung und ein kontrollierter Update-Prozess bleiben notwendig.
- SRI ersetzt HTTPS nicht. Auf einer HTTP-Seite kann ein Angreifer, der das Dokument veraendern kann, auch dessen Integritaetsmetadaten entfernen oder ersetzen.
- SRI garantiert keine Verfuegbarkeit. Ein Vendor-Update, eine Transformation, ein CORS-Fehler oder ein nicht erreichbares CDN kann dazu fuehren, dass die geschuetzte Ressource blockiert bleibt.
- SRI begrenzt nicht jede spaetere Anfrage. Ein kleiner Loader mit passenden Bytes kann weiterhin dynamischen Code oder Daten abrufen. Die Vertrauensanalyse muss einbeziehen, was das festgelegte Skript nach seinem Start tut.
- SRI ist keine digitale Signatur. Der Digest besitzt keine unabhaengige Herausgeberidentitaet. Wer sowohl HTML als auch Ressource aendern kann, kann beide Werte ersetzen.
Eine Content Security Policy ergaenzt SRI, anstatt es zu duplizieren. Eine CSP kann einschraenken, welche Origins oder Skriptformen eine Seite erlaubt; SRI prueft, ob eine bestimmte abgerufene Ressource den erwarteten Bytes entspricht. Self-Hosting kann die direkte Abhaengigkeit von einem Drittanbieter zur Laufzeit verringern, uebertraegt aber Verantwortung fuer Auslieferung, Patches und Monitoring auf den Websitebetreiber. Keine dieser Entscheidungen beseitigt die Notwendigkeit, die Abhaengigkeit zu verstehen.
Wann passt SRI?
SRI eignet sich gut fuer extern gehostetes, versioniertes JavaScript oder CSS, dessen exakte Bytes bis zu einem geplanten Update stabil bleiben sollen. Fuer eine URL, die absichtlich wechselnde Inhalte liefert, ist es ungeeignet, sofern der Anbieter keine unveraenderlichen Versionen bereitstellt oder die Website ihre Integration nicht neu gestalten kann. Bei einem dynamischen Tag Manager kann das alleinige Festlegen des ersten Loaders weniger Schutz bieten, als das Markup vermuten laesst.
Die praktische Frage lautet daher nicht: „Sollte jede externe Datei einen Hash erhalten?“ Sie lautet: „Laesst sich diese Abhaengigkeit auf ein geprueftes, unveraenderliches Artefakt mit einem von uns betreibbaren Update-Prozess reduzieren?“ Wenn ja, uebertraegt SRI dem Browser eine kleine, aber bedeutsame Durchsetzungsaufgabe. Wenn nein, zeigt die Abweichung eine groessere Architekturentscheidung: dynamische Kontrolle durch Drittanbieter akzeptieren, sorgfaeltiger isolieren, ein genehmigtes Artefakt selbst hosten, die Abhaengigkeit ersetzen oder sie entfernen.
Fazit
Subresource Integrity verwandelt ein implizites Versprechen in einen vom Browser erzwungenen Vergleich: Dieses Skript oder Stylesheet muss diesen erwarteten Bytes entsprechen. Eine korrekte Bereitstellung erfordert das exakte Artefakt, einen passenden Digest, CORS fuer Cross-Origin-Ressourcen, Browsertests und einen Prozess, der URL und Hash gemeinsam aktualisiert.
Die Grenzen sind ebenso wichtig wie die Syntax. SRI bestaetigt keine Urheberschaft, entdeckt keine Schwachstellen, erhaelt keine Verfuegbarkeit und baendigt keine beliebigen dynamischen Loader. Wo Bytes jedoch stabil bleiben sollen, reduziert es eine Vertrauensentscheidung gegenueber Drittanbietern auf etwas, das der Browser tatsaechlich pruefen kann.
