Trusted Types API
Limited availability
This feature is not Baseline because it does not work in some of the most widely-used browsers.
Hinweis: Diese Funktion ist in Web Workers verfügbar.
Die Trusted Types API gibt Webentwicklern eine Möglichkeit, sicherzustellen, dass Eingaben durch eine benutzerspezifizierte Transformationsfunktion geleitet wurden, bevor sie an eine API weitergegeben werden, die diese Eingaben ausführen könnte. Dies kann helfen, clientseitige Cross-Site-Scripting (XSS)-Angriffe zu verhindern. Am häufigsten bereinigt die Transformationsfunktion die Eingabe.
Konzepte und Verwendung
Clientseitige oder DOM-basierte XSS-Angriffe treten auf, wenn von einem Angreifer erstellte Daten an eine Browser-API übergeben werden, die diese Daten als Code ausführt. Diese APIs sind als Injection-Sinks bekannt.
Die Trusted Types API unterscheidet drei Arten von Injection-Sinks:
- HTML-Sinks: APIs, die ihre Eingaben als HTML interpretieren, wie
Element.innerHTMLoderdocument.write(). Diese APIs könnten JavaScript ausführen, wenn es in das HTML eingebettet ist, beispielsweise in<script>-Tags oder Event-Handler-Attributen. - JavaScript-Sinks: APIs, die ihre Eingaben als JavaScript interpretieren, wie
eval()oderHTMLScriptElement.text. - JavaScript-URL-Sinks: APIs, die ihre Eingaben als URL eines Skripts interpretieren, wie
HTMLScriptElement.src.
Eine der Hauptverteidigungen gegen DOM-basierte XSS-Angriffe besteht darin, sicherzustellen, dass Eingaben vor der Weitergabe an einen Injection-Sink sicher sind.
In der Trusted Types API definiert ein Entwickler ein Policy-Objekt, das Methoden enthält, die Eingaben, die an einen Injection-Sink gebunden sind, transformieren, um sie sicher zu machen. Die Richtlinie kann für die verschiedenen Arten von Sinks unterschiedliche Methoden definieren:
- Für HTML-Sinks bereinigt die Transformationsfunktion typischerweise die Eingabe, beispielsweise durch die Verwendung einer Bibliothek wie DOMPurify.
- Für JavaScript- und JavaScript-URL-Sinks kann die Policy die Sinks vollständig deaktivieren oder bestimmte vordefinierte Eingaben zulassen (zum Beispiel spezifische URLs).
Die Trusted Types API stellt dann sicher, dass Eingaben durch die geeignete Transformationsfunktion geleitet werden, bevor sie in den Sink gelangen.
Das heißt, mit der API können Sie Ihre Richtlinie an einer Stelle definieren und dann sicher sein, dass alle Daten, die an einen Injection-Sink weitergegeben werden, durch die Richtlinie geleitet wurden.
Hinweis:
Die Trusted Types API liefert keine eigene Richtlinie oder Transformationsfunktionen: Der Entwickler definiert seine eigene Richtlinie, die die gewünschten Transformationen enthält.
Die API besteht aus zwei Hauptkomponenten:
- Eine JavaScript-API ermöglicht es einem Entwickler, Daten zu bereinigen, bevor sie an einen Injection-Sink weitergegeben werden.
- Zwei CSP-Direktiven erzwingen und steuern die Verwendung der JavaScript-API.
Die Trusted Types JavaScript-API
In der Trusted Types API:
- Die globale Eigenschaft
trustedTypes, verfügbar in sowohlWindowals auchWorkerKontexten, wird verwendet, umTrustedTypePolicy-Objekte zu erstellen. - Ein
TrustedTypePolicy-Objekt wird verwendet, um Trusted-Type-Objekte zu erstellen: Dies geschieht, indem die Daten durch eine Transformationsfunktion geleitet werden. - Trusted-Type-Objekte repräsentieren Daten, die durch die Richtlinie gegangen sind und daher sicher an einen Injection-Sink weitergegeben werden können. Es gibt drei Arten von Trusted-Type, die den verschiedenen Arten von Injection-Sinks entsprechen:
TrustedHTMList für die Übergabe an einen Sink, der die Daten als HTML rendert.TrustedScriptist für die Übergabe an einen Sink, der die Daten als JavaScript ausführt.TrustedScriptURList für die Übergabe an einen Sink, der die Daten als URL zu einem Skript analysiert.
Mit dieser API verwenden Sie anstatt einer Zeichenkette, die Sie an einen Injection-Sink wie innerHTML übergeben, ein TrustedTypePolicy, um aus der Zeichenkette ein TrustedHTML-Objekt zu erstellen und dieses dann in den Sink zu übergeben, um sicherzustellen, dass die Zeichenkette durch eine Transformationsfunktion geleitet wurde.
Zum Beispiel erstellt dieser Code eine TrustedTypePolicy, die TrustedHTML-Objekte erzeugen kann, indem sie die Eingabezeichenfolgen mit der DOMPurify-Bibliothek bereinigt:
const policy = trustedTypes.createPolicy("my-policy", {
createHTML: (input) => DOMPurify.sanitize(input),
});
Anschließend können Sie dieses policy-Objekt verwenden, um ein TrustedHTML-Objekt zu erstellen und dieses in den Injection-Sink zu übergeben:
const userInput = "<p>I might be XSS</p>";
const element = document.querySelector("#container");
const trustedHTML = policy.createHTML(userInput);
element.innerHTML = trustedHTML;
Verwendung einer CSP zur Durchsetzung von Trusted Types
Die oben beschriebene API ermöglicht es Ihnen, Daten zu bereinigen, aber sie stellt nicht sicher, dass Ihr Code niemals Eingaben direkt an einen Injection-Sink weitergibt: Sie verhindert nicht, dass Sie eine Zeichenkette in innerHTML übergeben.
Um durchzusetzen, dass immer ein Trusted Type übergeben werden muss, fügen Sie die require-trusted-types-for-Direktive in Ihre CSP ein.
Mit dieser gesetzten Direktive führt die Übergabe von Zeichenketten an Injection-Sinks zu einer TypeError-Ausnahme:
const userInput = "<p>I might be XSS</p>";
const element = document.querySelector("#container");
element.innerHTML = userInput; // Throws a TypeError
Zusätzlich kann die trusted-types-CSP-Direktive verwendet werden, um zu steuern, welche Richtlinien Ihr Code erstellen darf. Wenn Sie eine Richtlinie mit trustedTypes.createPolicy() erstellen, geben Sie einen Namen für die Richtlinie an. Die trusted-types-CSP-Direktive listet akzeptable Richtliniennamen auf, sodass createPolicy() eine Ausnahme auslöst, wenn ein nicht aufgelisteter Name übergeben wird. Dies verhindert, dass ein Teil Ihres Webanwendungscodes eine Richtlinie erstellt, die Sie nicht erwartet haben.
Die Standardrichtlinie
In der Trusted Types API können Sie eine Standardrichtlinie definieren. Dies hilft Ihnen, alle Stellen in Ihrem Code zu finden, an denen Sie noch Zeichenketten in Injection-Sinks übergeben, damit Sie den Code neu schreiben können, um stattdessen Trusted Types zu erstellen und zu übergeben.
Wenn Sie eine Richtlinie mit dem Namen "default" erstellen und Ihre CSP die Verwendung von Trusted Types erzwingt, wird jedes Zeichenkettenargument, das an Injection-Sinks übergeben wird, automatisch an diese Richtlinie übergeben. Angenommen, wir erstellen eine Richtlinie so:
trustedTypes.createPolicy("default", {
createHTML(value) {
console.log("Please refactor this code");
return sanitize(value);
},
});
Mit dieser Richtlinie ruft der Browser die createHTML()-Methode der Richtlinie auf und weist das Ergebnis dem Sink zu, wenn Ihr Code eine Zeichenkette innerHTML zuweist:
const userInput = "<p>I might be XSS</p>";
const element = document.querySelector("#container");
element.innerHTML = userInput;
// Logs "Please refactor this code"
// Assigns the result of sanitize(userInput)
Wenn die Standardrichtlinie null oder undefined zurückgibt, wirft der Browser eine TypeError, wenn er das Ergebnis dem Sink zuweist:
trustedTypes.createPolicy("default", {
createHTML(value) {
console.log("Please refactor this code");
return null;
},
});
const userInput = "<p>I might be XSS</p>";
const element = document.querySelector("#container");
element.innerHTML = userInput;
// Logs "Please refactor this code"
// Throws a TypeError
Hinweis: Es wird empfohlen, die Standardrichtlinie nur während der Übergangszeit von Legacy-Code, der Eingaben direkt an Injection-Sinks weiterleitet, zu Code, der Trusted Types explizit verwendet, zu verwenden.
Injection-Sink-Schnittstellen
In diesem Abschnitt finden Sie eine Liste von "direkten" Injection-Sink-Schnittstellen.
Beachten Sie, dass es Fälle gibt, in denen unzuverlässige Zeichenketten "indirekt injiziert" werden können, wie wenn eine unzuverlässige Zeichenkette als Knoten eines Skriptelements hinzugefügt und dann das Element dem Dokument hinzugefügt wird. Diese Fälle werden ausgewertet, wenn das unzuverlässige Skript ins Dokument eingefügt wird.
TrustedHTML
Document.execCommand()mit einemcommandNamevon"insertHTML"Document.parseHTMLUnsafe_static()Document.write()Document.writeln()DOMParser.parseFromString()Element.innerHTMLElement.insertAdjacentHTMLElement.outerHTMLElement.setHTMLUnsafe()HTMLIFrameElement.srcdocRange.createContextualFragment()ShadowRoot.innerHTMLShadowRoot.setHTMLUnsafe()
TrustedScript
eval()Element.setAttribute()(valueArgument)Element.setAttributeNS()(valueArgument)Function()KonstruktorHTMLScriptElement.innerTextHTMLScriptElement.textContentHTMLScriptElement.textwindow.setTimeout()undWorkerGlobalScope.setTimeout()(codeArgument)window.setInterval()undWorkerGlobalScope.setInterval()(codeArgument)
TrustedScriptURL
HTMLScriptElement.srcServiceWorkerContainer.register()SvgAnimatedString.baseValWorkerGlobalScope.importScripts()urlArgument für denWorker()KonstruktorurlArgument für denSharedWorker()Konstruktor
Unterstützung von Trusted Types in verschiedenen Browsern
Die Trusted Types API ist noch nicht in allen modernen Browsern verfügbar, kann jedoch dank Kompatibilitätshilfen, die von der W3C erstellt wurden, überall genutzt werden.
- Der vollständige Polyfill definiert die JavaScript-API, versucht die CSP vom aktuellen Dokument abzuleiten und erzwingt die Verwendung von Trusted Types basierend auf der abgeleiteten CSP.
- Der nur API Polyfill definiert nur die JavaScript-API und enthält nicht die Fähigkeit, mithilfe einer CSP die Verwendung von Trusted Types zu erzwingen.
Zusätzlich zu diesen zwei Polyfills stellt die W3C ein sogenanntes tinyfill bereit, das wir im Folgenden ausführlicher erklären werden.
Beachten Sie, dass solange Sie Ihren Code in einem unterstützenden Browser mit aktivierter CSP-Durchsetzung getestet haben, Sie den vollständigen Polyfill nicht in anderen Browsern verwenden müssen — Sie können die gleichen Vorteile mit dem nur API Polyfill oder dem tinyfill erzielen.
Dies liegt daran, dass die Durchsetzung Sie dazu zwingt, Ihren Code so zu refaktorisieren, dass alle Daten durch die Trusted Types API geleitet werden (und daher durch eine Bereinigungsfunktion gegangen sind), bevor sie an einen Injection-Sink weitergegeben werden. Wenn Sie den refaktorisierten Code dann in einem anderen Browser ohne Durchsetzung ausführen, wird er immer noch die gleichen Codepfade durchlaufen und Ihnen denselben Schutz bieten.
Trusted Types tinyfill
In diesem Abschnitt betrachten wir, wie das Trusted Types tinyfill eine Website schützen kann, obwohl es Trusted Types überhaupt nicht unterstützt.
Das Trusted Types tinyfill ist einfach dies:
if (typeof trustedTypes === "undefined")
trustedTypes = { createPolicy: (n, rules) => rules };
Es stellt eine Implementierung von trustedTypes.createPolicy() bereit, die einfach das policyOptions Objekt zurückgibt, das übergeben wurde. Das policyOptions-Objekt definiert Bereinigungsfunktionen für Daten, und diese Funktionen sollen Zeichenketten zurückgeben.
Mit diesem Tinyfill, angenommen, wir erstellen eine Richtlinie:
const policy = trustedTypes.createPolicy("my-policy", {
createHTML: (input) => DOMPurify.sanitize(input),
});
In Browsern, die Trusted Types unterstützen, wird dies eine TrustedTypePolicy zurückgeben, die ein TrustedHTML-Objekt erstellt, wenn wir policy.createHTML() aufrufen. Das TrustedHTML-Objekt kann dann an einen Injection-Sink übergeben werden, und wir können erzwingen, dass der Sink einen Trusted Type anstelle einer Zeichenkette empfangen hat.
In Browsern, die Trusted Types nicht unterstützen, wird dieser Code ein Objekt mit einer createHTML()-Funktion zurückgeben, das seine Eingaben bereinigt und sie als Zeichenkette zurückgibt. Die bereinigte Zeichenkette kann dann an einen Injection-Sink übergeben werden.
const userInput = "I might be XSS";
const element = document.querySelector("#container");
const trustedHTML = policy.createHTML(userInput);
// In supporting browsers, trustedHTML is a TrustedHTML object.
// In non-supporting browsers, trustedHTML is a string.
element.innerHTML = trustedHTML;
// In supporting browsers, this will throw if trustedHTML
// is not a TrustedHTML object.
In jedem Fall erhält der Injection-Sink bereinigte Daten, und da wir die Verwendung der Richtlinie im unterstützenden Browser erzwingen konnten, wissen wir, dass dieser Codepfad die Bereinigungsfunktion auch im nicht unterstützenden Browser durchläuft.
Schnittstellen
TrustedHTML-
Repräsentiert eine Zeichenkette, die in einen Injection-Sink eingefügt werden soll, der sie als HTML rendert.
TrustedScript-
Repräsentiert eine Zeichenkette, die in einen Injection-Sink eingefügt werden soll, die dazu führen könnte, dass das Skript ausgeführt wird.
TrustedScriptURL-
Repräsentiert eine Zeichenkette, die in einen Injection-Sink eingefügt werden soll, der sie als URL einer externen Skriptressource interpretiert.
TrustedTypePolicy-
Definiert die Funktionen, die zum Erstellen der oben genannten Trusted-Type-Objekte verwendet werden.
TrustedTypePolicyFactory-
Erstellt Richtlinien und prüft, ob Trusted Type-Objektinstanzen über eine der Richtlinien erstellt wurden.
Erweiterungen zu anderen Schnittstellen
Window.trustedTypes-
Gibt das
TrustedTypePolicyFactory-Objekt zurück, das mit dem globalen Objekt im Hauptthread verbunden ist. Dies ist der Einstiegspunkt zur Verwendung der API im Window-Thread. WorkerGlobalScope.trustedTypes.-
Gibt das
TrustedTypePolicyFactory-Objekt zurück, das mit dem globalen Objekt in einem Worker verbunden ist.
Erweiterungen zu HTTP
Content-Security-Policy Direktiven
require-trusted-types-for-
Erzwingt, dass Trusted Types an DOM XSS Injection-Sinks übergeben werden.
trusted-types-
Wird verwendet, um eine Whitelist von Trusted Types Richtliniennamen anzugeben.
Content-Security-Policy Schlüsselwörter
trusted-types-eval-
Erlaubt die Verwendung von
eval()und ähnlichen Funktionen, jedoch nur, wenn Trusted Types unterstützt und erzwungen werden.
Beispiele
Im untenstehenden Beispiel erstellen wir eine Richtlinie, die TrustedHTML-Objekte mit TrustedTypePolicyFactory.createPolicy() erstellt. Wir können dann TrustedTypePolicy.createHTML() verwenden, um eine bereinigte HTML-Zeichenfolge zu erstellen, die in das Dokument eingefügt wird.
Der bereinigte Wert kann dann mit Element.innerHTML verwendet werden, um sicherzustellen, dass keine neuen HTML-Elemente injiziert werden können.
<div id="myDiv"></div>
const escapeHTMLPolicy = trustedTypes.createPolicy("myEscapePolicy", {
createHTML: (string) =>
string
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/"/g, """)
.replace(/'/g, "'"),
});
let el = document.getElementById("myDiv");
const escaped = escapeHTMLPolicy.createHTML("<img src=x onerror=alert(1)>");
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped;
Lesen Sie mehr über dieses Beispiel und entdecken Sie andere Möglichkeiten zur Bereinigung von Eingaben im Artikel DOM-basierte Cross-Site-Scripting-Schwachstellen mit Trusted Types verhindern.
Spezifikationen
| Specification |
|---|
| Trusted Types> |
Browser-Kompatibilität
Loading…