Tutorial: Ein minifiziertes Fremdskript lesen, bevor es auf die Seite darf

Management Summary
Fremdskripte bringen externe Dienste auf eine Website, können aber auch Seiteninformationen lesen und andere Server kontaktieren. Minifizierte Skripte sind für kleine Downloads in eine schwer lesbare Form verdichtet. Der Beitrag erklärt, wie die Betrachtung von Code und Verhalten die geplanten Zugriffe vor dem Einbau verständlich macht. Das unterstützt die Kontrolle über Datenweitergabe und spätere Änderungen. Was ein Anbieter nach dem Empfang mit Informationen macht, lässt sich aus dem Website-Code allein jedoch nicht vollständig erkennen.
Inhalt
Ein direkt in einer Seite ausgeführtes Fremdskript kann mit den Rechten dieser Seite auf den DOM und viele Browserfunktionen zugreifen. Der DOM ist die Darstellung der Seite im Browser, einschließlich Texten, Formularen und anderen Elementen. Browsergrenzen gelten weiterhin: Fremde Frames, HttpOnly-Cookies und berechtigungspflichtige Schnittstellen sind nicht einfach frei zugänglich. Die Prüfung muss deshalb den tatsächlichen Einbindungskontext feststellen.
Formatieren und Stichwortsuchen helfen bei der ersten Sichtung. Sechs Suchläufe erfassen aber nicht jede Fähigkeit, beweisen keine Harmlosigkeit und ersetzen keine Sicherheitsprüfung. Ein brauchbares Ergebnis ist ein nachvollziehbarer Befund: genaue Datei, mögliche Fähigkeiten, beobachtetes Verhalten, benötigte Ziele und offene Fragen.
Eine reproduzierbare Kopie als Ausgangspunkt
Das folgende Bash-Beispiel benötigt curl, sha256sum und eine bereits installierte, freigegebene Version von js-beautify. Vor der Nutzung ersetzt die echte Anbieteradresse die reservierte Beispieladresse. Ein eigener Prüfungsordner erhält jeden datierten Schnappschuss. Der Download speichert Header und endgültige Adresse, bricht bei HTTP-Fehlern ab und erlaubt nur HTTPS-Weiterleitungen. Die heruntergeladene Datei wird dabei nicht ausgeführt.
set -eu
curl --fail --show-error --silent --location \
--proto '=https' --proto-redir '=https' \
--connect-timeout 10 --max-time 60 \
--dump-header widget.headers.txt \
--write-out '%{url_effective}\n' \
--output widget.raw.js \
'https://cdn.vendor.example/widget.js' > widget.final-url.txt
test -s widget.raw.js
sha256sum widget.raw.js > widget.sha256
js-beautify --version
js-beautify widget.raw.js -o widget.pretty.jsAuch nach erfolgreichem Download sind Inhalt und Content-Type zu prüfen: Eine HTML-Anmeldeseite mit Status 200 ist nicht das erwartete JavaScript. Formatiererversion und Abrufzeit gehören ins Protokoll. Für Prüfsummen bleiben die unveränderten Bytes maßgeblich; die formatierte Kopie dient nur dem Lesen. Der Größenunterschied ist weder ein Sicherheitsmaß noch eine zuverlässige Messung der Transportkompression.
Formatieren stellt beim Bau entfernte Namen, Kommentare oder Quellstrukturen nicht wieder her. Source Maps ordnen Stellen der ausgelieferten Datei dem ursprünglichen Quellcode zu. Vorhandene Zuordnungsdateien erleichtern die Sichtung, müssen aber zur ausgelieferten Datei passen. Auch DevTools kann Antwortinhalte speichern und Netzwerkprotokolle exportieren; eine Browserprüfung lässt sich daher durchaus dokumentieren. Vor einer Weitergabe benötigen aufgezeichnete Adressen und Nutzdaten gegebenenfalls eine Bereinigung.
Sechs Suchläufe nach möglichen Fundstellen
Diese Beispiele erfassen einige verbreitete Schreibweisen. Ein Treffer kann in einem Kommentar oder ungenutzten Zweig stehen; ein fehlender Treffer schließt die Fähigkeit nicht aus. Ein Skript kann etwa globalThis["fe" + "tch"](...) aufrufen, einen Alias nutzen oder weiteren Code laden. Die sechs Gruppen strukturieren die Prüfung und erteilen keine Freigabe.
# Network-related candidates
grep -nE 'fetch[[:space:]]*\(|XMLHttpRequest|sendBeacon|WebSocket|EventSource|new[[:space:]]+Image' widget.pretty.js
# Storage and cookie candidates
grep -nE 'localStorage|sessionStorage|cookie|indexedDB|caches' widget.pretty.js
# Additional code or resource loading
grep -nE 'createElement|import[[:space:]]*\(|importScripts|Worker|\.src[[:space:]]*=' widget.pretty.js
# Input and form handling
grep -nE 'addEventListener|oninput|onkeydown|onsubmit|FormData|\.value' widget.pretty.js
# Device and rendering features
grep -nE 'getContext|toDataURL|AudioContext|hardwareConcurrency|RTCPeerConnection' widget.pretty.js
# Literal HTTP(S) host candidates only
grep -oiE 'https?://[a-z0-9.-]+' widget.pretty.js | sort -uDie Speichersuche unterscheidet nicht zwischen Lesen und Schreiben. Sitzungsspeicher entspricht keiner unbegrenzten Aufbewahrung. Bei Eingaben zählen das tatsächliche Element, weitergeleitete Ereignisse, ausgelesene Werte und deren spätere Übertragung. Canvas-, Audio- oder WebRTC-Nutzung allein beweist kein Fingerprinting: Auch Funktionstests und legitime Darstellung kommen infrage. Zweck und Datenfluss entscheiden über den Befund.
Die Einwilligungsfrage lässt sich nicht allein aus „Speicherung plus Übertragung“ ableiten. Auch das Auslesen von Endgeräteinformationen kann ohne neues Cookie relevant sein. Ein Skript ohne Stichworttreffer ist nicht automatisch eine harmlose Darstellungshilfe. Zweck, Zugriffs- und Speichervorgänge, personenbezogene Daten und anwendbare Ausnahmen benötigen eine eigene Bewertung. Die EDSA-Leitlinien beschreiben den technischen Anwendungsbereich über klassische Cookies hinaus.

Minifizierung und Verschleierung
Minifizierung verkleinert den Code, etwa durch Entfernen von Leerzeichen und Kürzen interner Namen; Verschleierung soll das Verständnis erschweren. Kodierte Zeichenkettenlisten, berechnete Eigenschaftsnamen und dynamische Codeerzeugung sind Prüfansätze, aber kein Beweis für schädliche Absicht. Base64-Dekodierung mit atob hat legitime Anwendungen außerhalb von Bildern. Umgekehrt kann ein berechneter Eigenschaftszugriff eine einfache Suche bereits ohne aufwendige Verschleierung umgehen.
grep -nE 'eval[[:space:]]*\(|Function[[:space:]]*\(|atob[[:space:]]*\(|String\.fromCharCode|\\x[0-9a-fA-F]{2}' widget.pretty.jsAuch verschleierter Code kann sich durch Dekodierung, Source Maps oder vertiefte statische Analyse erschließen. Ein isolierter Laufzeittest liefert zusätzliche Nachweise, allerdings nur für tatsächlich durchlaufene Pfade. Eine Testseite enthält künstliche Daten und keine aktiven Produktionskonten. Zur Verhaltensprüfung gehört unbekannter Code nicht in einen gewöhnlichen angemeldeten Browser oder auf die Produktionsseite.
Aus Host-Kandidaten entsteht nicht automatisch eine CSP
Der Host-Ausdruck oben erfasst bewusst nur einfache ausgeschriebene HTTP(S)-Präfixe. Relative Adressen, protokollrelative URLs, WebSocket-Adressen, kodierte Zeichenketten und zusammengesetzte Ziele fehlen; auch Portangaben gehen verloren. Kommentare und Dokumentationsadressen können irrelevante Treffer liefern. Eine Content Security Policy (CSP) legt fest, aus welchen Quellen der Browser Skripte, Verbindungen und andere Ressourcen beziehen darf. Eine brauchbare Zielliste verbindet Codekontext, tatsächliche Anfragen, Weiterleitungen und Anbieterdokumentation.
Der Ressourcentyp bestimmt die CSP-Anweisung: Skriptladen, API-Verbindungen und Bildabrufe sind unterschiedliche Vorgänge. Ein Host im Text reicht nicht als Grund für eine Freigabe. Das folgende Nur-Bericht-Beispiel illustriert eine kleine fiktive Website. Domains und Berichtsempfänger sind Platzhalter; die vollständige Anwendungsrichtlinie benötigt eine eigene Prüfung.
Reporting-Endpoints: csp="https://reports.site.example/csp"
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://cdn.vendor.example; connect-src 'self' https://api.vendor.example; img-src 'self' https://images.vendor.example; report-to cspJeder Header steht in einer HTTP-Headerzeile. Der Berichtsendpunkt muss tatsächlich existieren. Report-Only beobachtet Verstöße, blockiert aber nicht. Berichte hängen von Browserunterstützung, Zustellung und durchlaufenen Pfaden ab. Fehlende Meldungen beweisen keine Vollständigkeit, und eine feste Woche deckt nicht alle Bedingungen ab. Konsolen- und Netzwerkbeobachtung bleiben Teil des Tests.
Eine Host-Freigabeliste fixiert keine Dateiinhalte. Ein weiteres Skript vom bereits erlaubten Host kann ohne zusätzlichen Host-Eintrag laden. Bei Vertrauen über Nonce oder Hash und 'strict-dynamic' können unterstützende Browser außerdem dynamisch geladene Abhängigkeiten ohne gesonderte Host-Einträge zulassen. CSP schließt daher nicht jede Lücke eines unveränderten Laders.
SRI bindet die geprüften Bytes
Für eine geeignete stabile Skriptantwort vergleicht Subresource Integrity die Bytes vor der Ausführung mit einer erwarteten Prüfsumme. Die Prüfsumme stammt aus der geprüften unveränderten Datei, nicht aus der formatierten Kopie. Dieses Python-Beispiel gibt den tatsächlichen SHA-384-Integritätswert aus:
import base64
import hashlib
from pathlib import Path
raw = Path("widget.raw.js").read_bytes()
digest = base64.b64encode(hashlib.sha384(raw).digest()).decode("ascii")
print("sha384-" + digest)Die vollständige Ausgabe ersetzt den folgenden Platzhalter. Der Platzhalter ist ausdrücklich keine gültige Prüfsumme für eine Einbindung.
<script src="https://cdn.vendor.example/widget.js"
integrity="sha384-REPLACE_WITH_REVIEWED_BASE64_DIGEST"
crossorigin="anonymous"></script>Eine abweichende Antwort besteht die Integritätsprüfung nicht. Für diesen Fall benötigt die Anwendung ein festgelegtes Verhalten; ein automatisches Übernehmen der gerade ausgelieferten Anbieter-Prüfsumme wäre keine erneute Prüfung. Bei fremdem Ursprung setzt SRI außerdem eine passende CORS-Antwort voraus. crossorigin="anonymous" verwendet CORS mit dem Berechtigungsmodus same-origin: Bei fremdem Ursprung entfallen Zugangsdaten, bei gleichem Ursprung können weiterhin Zugangsdaten mitgesendet werden.
Ein veränderlicher Tag-Container ist nicht grundsätzlich unvereinbar mit Prüfsummen. Dynamische oder personalisierte Antworten, fehlende CORS-Unterstützung und häufige Veröffentlichungen können eine stabile SRI-Einbindung jedoch ungeeignet machen oder außerhalb der Anbieterunterstützung liegen. Ohne Fixierung bleiben Veröffentlichungskontrollen, geprüfte Versionen und Überwachung erforderlich. Keine dieser Maßnahmen bestätigt beliebigen zukünftigen Code.
Fragen und Antworten
Erfasst die Prüfsumme des Laders alle Abhängigkeiten?
Nein. Die Prüfsumme an einem Skript-Element gilt für die damit abgerufene Ressource, nicht für jedes später geladene Skript oder jede Konfigurationsantwort. Ein dynamisch erzeugtes Skript kann eigene Integritätsmetadaten erhalten, sofern der Lader das unterstützt. Ansonsten benötigt jede Abhängigkeit eine gesonderte Bewertung; ein erlaubter Host ist keine Integritätsgarantie.
Beweist eine unveränderte wöchentliche Prüfsumme gleiches Verhalten?
Nein. Identische Bytes können wegen externer Konfiguration, Zeitpunkt, Standort, Einwilligung, Kontozustand oder geänderter Abhängigkeiten anders reagieren. Eine geänderte Prüfsumme ist ein Prüfhinweis und kein Urteil. Der Vergleichsrhythmus richtet sich nach Aktualisierungsverfahren und Risiko der Einbindung; Laufzeittests decken zusätzlich relevante Bedingungen ab.
Was gehört zur Prüfung einer Aktualisierung?
- Ein neuer unveränderter Schnappschuss mit Abrufnachweis neben der zuvor akzeptierten Version.
- Ein Vergleich von Code, möglichen Zielen und Abhängigkeiten im Zusammenhang; geänderte Minifizierung kann Zeilenvergleiche unübersichtlich machen.
- Isolierte Tests für relevante Seiten, Einwilligungszustände und Interaktionen samt Netzwerk- und Speicherbeobachtung.
- Eine dokumentierte Entscheidung zu jedem neuen Ziel oder Funktionsumfang vor einer Änderung der CSP oder akzeptierten Prüfsumme.
Serverseitige Nutzung, Aufbewahrung und Weitergabe lassen sich nicht allein aus Browsercode feststellen. Dazu gehören Anbieternachweise und die einschlägige Vertragsdokumentation. Die technische Prüfung präzisiert die Fragen und verifiziert nicht eigenständig die gesamte Verarbeitungskette des Anbieters.
Quellen
- MDN: JavaScript-Dokumentation
- MDN: Zugriff auf JavaScript-Eigenschaften
- MDN: Regeln für gleichen Ursprung
- MDN: Document.cookie
- Chrome DevTools: Ursprünglichen Code mit Source Maps prüfen
- Chrome DevTools: Netzwerkfunktionen
- js-beautify: Projektdokumentation und Befehlszeile
- curl: Befehlszeilenhandbuch
- EDSA: Leitlinien 2/2023 zum technischen Anwendungsbereich von Artikel 5 Absatz 3, Version 2.0
- MDN: Content-Security-Policy script-src
- MDN: Content-Security-Policy-Report-Only
- W3C: Content Security Policy Stufe 3
- MDN: Subresource Integrity
- W3C: Subresource Integrity
- WHATWG HTML: Attribute für CORS-Einstellungen


