Die Subresource Integrity (SRI) ist ein wichtiger Bestandteil zur Sicherheit von Webseiten

Die Subresource Integrity (SRI) ist ein Sicherheitsverfahren, das davor schützt, nachträglich veränderte Scripte oder CSS-Dateien in Webseiten zu laden.

Dabei wird auf Hash-Werte zurückgegriffen die eine geladene Datei eindeutig identifizierbar macht.

D. h.: entspricht der angegebene Hash nicht dem der externen Datei, wird diese nicht geladen.
Man erhält dadurch immer genau die Version der Datei, die man Aufgrund des Hashes erwartet.

Angenommen die externe Resource wurde geändert

3. User Agent verweigert die Datei
1. Anforderung einer Resource mit SRI-Hash
Server mit kompromittierten Dateien.
2. Server liefert Datei mit falschem Hash.

Überprüfung der SRI einer Webseite

Das einfachste Mittel zum Überprüfen der SRI einer Seite ist die Webseite Dort können Sie eine URL eingeben und sehen ob alle externen Scripte oder CSS-Dateien mit SRI geladen wurden.
Screenshot: Kein RSI Fehler
Mozilla-Observatory Screenshot: Dateien mit SRI geladen.
Screenshot: RSI Fehler
Mozilla-Observatory Screenshot: Dateien nicht mit SRI geladen.

Implementierung auf der Webseite

integrity
Hier folgt nach der Angabe des Hash-Algorithmus (als Präfix), getrennt durch einen "-", der base64 kodierte Hash.

integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
    

Es können hier mehrere Hashes angeben werden. Diese werden durch ein Leerzeichen getrennt.

<script src="/hello_world.js"
	integrity="sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO
              sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw=="
	crossorigin="anonymous">
</script>
    
In diesem Fall wählt der User-Agent die stärkste Hash-Funktion aus, um die Datei zu überprüfen.

Konforme User-Agents müssen die Hash-Funktionen sha256, sha384 und sha512 unterstützen.
crossorigin

crossorigin="anonymous"
    

Wenn die Anfrage nicht den gleichen Ursprung hat, muss hier anonymous angegeben werden. Ist dies nicht der Fall behandelt der Browser die Datei, als ob das Integritätsattribut nicht gesetzt ist. Dadurch ist geht die Sicherheit duch SRI wieder verloren.

Erstellen einer SRI

Online

Die Hashes können z. B. auf der Seite SRI Hash Generator erzeugt werden.

Kommandozeile

Mit openSSL:

cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A
    
oder mit shasum:

shasum -b -a 384 FILENAME.js | awk '{ print $1 }' | xxd -r -p | base64
    

PHP


<?php
function checksum($input) {
    $hash = hash('sha256', $input, true);
    $hash_base64 = base64_encode($hash);
    return "sha256-$hash_base64"; }
?>

CDN Anbieter

CDNs wie z. B. jsDelivr bieten die Möglichkeit die SRI automatisch zu erzeugen:
Screenshot: SRI jsDelivr
jsDelivr Screenshot: Auswahl mit SRI.

Automatische Erzeugung

Eine leider oft gezeigte Methode die Hashes, z. B. über PHP, automatisch zu erzeugen ist folgende:

<?php
$data = file_get_contents("https://code.jquery.com/jquery-3.6.0.min.js");
echo base64_encode(hash("sha256", $data, true));
>

Mit dieser Methode wird der Sicherheitsmechanismus der SRI ausgehebelt. Damit läßt sich nicht mehr feststellen ob die Ressource kompromittiert ist, da der User-Agent keinen Vergleich hat, sondern nur den Hash der externen Datei und dieser wird immer stimmen.
Der Hash muss bei so einer Vorgehensweise nicht von der externen sondern von einer sicheren lokalen Ressource erzeugt werden.
Rein aus Performance Gründen sollte dies nicht bei jedem Seiten Aufruf geschehen, sondern nur wenn sich die Dateien geändert haben.

Fallback

Sollte das Laden der externen Resource Fehlschlagen, ist es sinnvoll auf eine lokale Kopie zurückzugreifen.

<script>
window.jQuery ||
	document.write(
	'<script window.jQuery || document.write('<script src="/js/jquery.min.js"><\/script>');
</script>
    

Im Zusammenhang mit einer Content-Security-Policy (CSP) sollte das vorherige Beispiel nicht läuffähig sein, da hier ein Inline-Script erzeugt wird. Ein unsafe-inline, in der CSP, sollte bei Scripten vermieden werden.
Deshalb fügt man hier eine passende nonce ein:

<script nonce="anF1ZXJ5ZmsbGJhY2s=">
window.jQuery ||
	document.write(
	'<script window.jQuery || document.write('<script src="/js/jquery.min.js"><\/script>');
</script>
    
und paßt die CSPs entsprechend an:

default-src 'none';
script-src 'nonce-anF1ZXJ5ZmsbGJhY2s=';
connect-src 'self';
img-src 'self';
style-src 'self';
base-uri 'self';
form-action 'self'; 

Alternativ kann man auch das Script Subresource Integrity Fallback verwendet. Dieses lädt im Fehlerfall die lokale Resource.
Das Script muss vor allen anderen Resourcen geladen werden.

<script
	src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"
	integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
	data-sri-fallback="/js/jquery.min.js"
	crossorigin="anonymous">
</script>
    
Mit dem Data-Attribute data-sri-fallback wird hier die lokale Datei angegeben.

Dieses Script muss lokal vorhanden sein, sonst funktioniert bei einem CDN-Fehler auch dieses nicht.

Weitere Beispiele

Für CSS-Dateien:

<link
	href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css"
	rel="stylesheet"
    integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x"
    crossorigin="anonymous">

Test einer SRI

Wenn Sie eine SRI das erste Mal auf Ihrer Seite einsetzen, sollten Sie anschließend folgendes überprüfen:
  1. Gibt es Fehlermeldungen in der Browser-Konsole?
  2. Sind noch alle Funktionen der Seite gegeben?

Fehlermeldung in der Browser-Konsole

Screenshot: SRI-Fhler
FireFox Browser-Konsole Screenshot: Fehler mit SRI.
Screenshot: SRI-Fhler
Edge Browser-Konsole Screenshot: Fehler mit SRI.

Zusammenfassung

SRI über HTTP bringt wenig Nutzen, da die Übertagung beeinflußt werden kann. SRI ist nur im Zusammenspiel mit HTTPS sinnvoll.

SRI kann was CSP und HTTPS nicht können. Überprüfen ob auch der richtige Inhalt geladen wird.

Checkliste

  • Jede externe Resource (CSS oder Script) hat einen passendes integrity Attribut.
  • crossorigin="anonymous", sonst wird der Hash nicht überprüft.
  • Der Hash muss von einer bekannten, sicheren Quelle stammen.
  • Bei einer Änderung des externen Resource / Quelle muss der Hash neu erzeugt werden!

Mehr zum Thema

Tools

Weiterführende Informationen