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 bietet Webentwicklern eine Möglichkeit, sicherzustellen, dass Eingaben durch eine vom Benutzer spezifizierte Transformationsfunktion geleitet wurden, bevor sie an eine API übergeben werden, die diese Eingabe möglicherweise ausführt. Dies kann helfen, Client-seitige Cross-Site-Scripting (XSS)-Angriffe zu verhindern. Meistens bereinigt die Transformationsfunktion die Eingabe.
Konzepte und Verwendung
Client-seitige oder DOM-basierte XSS-Angriffe treten auf, wenn von einem Angreifer entworfene Daten an eine Browser-API übergeben werden, die diese Daten als Code ausführt. Diese APIs werden als Injection Sinks bezeichnet.
Die Trusted Types API unterscheidet drei Arten von Injection Sinks:
- HTML-Sinks: APIs, die ihre Eingabe als HTML interpretieren, wie zum Beispiel
Element.innerHTMLoderdocument.write(). Diese APIs könnten JavaScript ausführen, wenn es im HTML eingebettet ist, beispielsweise in<script>-Tags oder Ereignis-Handler-Attributen. - JavaScript-Sinks: APIs, die ihre Eingabe als JavaScript interpretieren, wie
eval()oderHTMLScriptElement.text. - JavaScript-URL-Sinks: APIs, die ihre Eingabe als URL eines Skripts interpretieren, wie
HTMLScriptElement.src.
Eine der Hauptverteidigungen gegen DOM-basierte XSS-Angriffe besteht darin, sicherzustellen, dass Eingaben sicher gemacht werden, bevor sie an ein Injection Sink übergeben werden.
In der Trusted Types API definiert ein Entwickler ein Policy-Objekt, das Methoden enthält, die Eingaben für ein Injection Sink so transformieren, dass sie sicher werden. Die Policy kann unterschiedliche Methoden für die verschiedenen Arten von Sinks definieren:
- Für HTML-Sinks bereinigt die Transformationsfunktion typischerweise die Eingabe, zum Beispiel durch den Einsatz einer Bibliothek wie DOMPurify.
- Für JavaScript- und JavaScript-URL-Sinks kann die Policy die Sinks vollständig deaktivieren oder bestimmte vordefinierte Eingaben (zum Beispiel spezifische URLs) zulassen.
Die Trusted Types API stellt dann sicher, dass Eingaben vor ihrer Übergabe an das Sink durch die entsprechende Transformationsfunktion geleitet werden.
Das bedeutet, die API ermöglicht es Ihnen, Ihre Policy an einem Ort zu definieren und dann sicherzustellen, dass alle Daten, die an ein Injection Sink übergeben werden, durch die Policy geleitet wurden.
Hinweis:
Die Trusted Types API liefert keine eigene Policy oder Transformationsfunktionen: Der Entwickler definiert seine eigene Policy, die die Transformationen enthält, die er anwenden möchte.
Die API besteht aus zwei Hauptteilen:
- Eine JavaScript-API ermöglicht es einem Entwickler, Daten zu bereinigen, bevor sie an ein Injection Sink übergeben werden.
- Zwei CSP-Directive erzwingen und kontrollieren die Nutzung der JavaScript-API.
Die Trusted Types JavaScript-API
In der Trusted Types API:
- Die globale Eigenschaft
trustedTypes, verfügbar sowohl imWindow- als auch imWorker-Kontext, 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 Policy geführt wurden und daher sicher an ein Injection Sink übergeben werden können. Es gibt drei Arten von Trusted Types, die den verschiedenen Arten von Injection Sinks entsprechen:
TrustedHTMLdient zur Übergabe an ein Sink, das die Daten als HTML rendert.TrustedScriptdient zur Übergabe an ein Sink, das die Daten als JavaScript ausführt.TrustedScriptURLdient zur Übergabe an ein Sink, das die Daten als URL eines Skripts analysiert.
Mit dieser API verwenden Sie anstelle eines Strings für ein Injection Sink wie innerHTML eine TrustedTypePolicy, um ein TrustedHTML-Objekt aus dem String zu erstellen, dann dieses in das Sink zu übergeben, und können sicher sein, dass der String durch eine Transformationsfunktion geleitet wurde.
Zum Beispiel erstellt dieser Code eine TrustedTypePolicy, die TrustedHTML-Objekte erzeugen kann, indem sie die Eingabestrings mit der DOMPurify-Bibliothek bereinigt:
const policy = trustedTypes.createPolicy("my-policy", {
createHTML: (input) => DOMPurify.sanitize(input),
});
Dann können Sie dieses policy-Objekt verwenden, um ein TrustedHTML-Objekt zu erstellen und dieses Objekt in das 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, gewährleistet jedoch nicht, dass Ihr Code niemals Eingaben direkt an ein Injection Sink übergibt: Das heißt, es verhindert nicht, dass Sie einen String in innerHTML übergeben.
Um sicherzustellen, dass immer ein Trusted Type übergeben wird, fügen Sie die require-trusted-types-for-Directive in Ihre CSP ein.
Mit dieser Directive führt das Übergeben von Strings in 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-Directive verwendet werden, um zu kontrollieren, welche Policies Ihr Code erstellen darf. Wenn Sie eine Policy mit trustedTypes.createPolicy() erstellen, übergeben Sie einen Namen für die Policy. Die trusted-types-CSP-Directive listet akzeptable Policy-Namen auf, sodass createPolicy() eine Ausnahme wirft, wenn ihm ein Name übergeben wird, der nicht in trusted-types aufgelistet war. Dies verhindert, dass ein Code in Ihrer Webanwendung eine Policy erstellt, die Sie nicht erwartet haben.
Die Standardpolicy
In der Trusted Types API können Sie eine Standardpolicy definieren. Dies hilft Ihnen, alle Stellen in Ihrem Code zu finden, in denen Sie noch Strings in Injection Sinks übergeben, damit Sie den Code umschreiben können, um explizit Trusted Types zu verwenden.
Wenn Sie eine Policy mit dem Namen "default" erstellen und Ihre CSP die Verwendung von Trusted Types erzwingt, wird jeder String, der an Injection Sinks übergeben wird, automatisch an diese Policy weitergeleitet. Nehmen wir zum Beispiel an, wir erstellen eine Policy wie diese:
trustedTypes.createPolicy("default", {
createHTML(value) {
console.log("Please refactor this code");
return sanitize(value);
},
});
Mit dieser Policy, wenn Ihr Code einen String an innerHTML zuweist, ruft der Browser die createHTML()-Methode der Policy auf und weist deren Ergebnis dem Sink zu:
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 Standardpolicy null oder undefined zurückgibt, dann wird der Browser einen TypeError werfen, 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 Standardpolicy nur zu verwenden, während Sie von Legacy-Code, der Eingaben direkt an Injection Sinks übergibt, zu Code übergehen, der Trusted Types explizit verwendet.
Injection Sink-Schnittstellen
Dieser Abschnitt stellt eine Liste von "direkten" Injection Sink-Schnittstellen bereit.
Beachten Sie, dass es Fälle gibt, in denen unzuverlässige Strings "indirekt injiziert" werden können, wie zum Beispiel, wenn ein unzuverlässiger String als Kindknoten eines Skriptelements hinzugefügt wird und dann das Element dem Dokument hinzugefügt wird. Diese Fälle werden bewertet, wenn das unzuverlässige Skript dem Dokument hinzugefügt wird.
TrustedHTML
Document.execCommand()mit einemcommandNamevon"insertHTML"Document.parseHTMLUnsafe()Document.write()Document.writeln()DOMParser.parseFromString()Element.innerHTMLElement.insertAdjacentHTMLElement.outerHTMLElement.setHTMLUnsafe()HTMLIFrameElement.srcdocRange.createContextualFragment()ShadowRoot.innerHTMLShadowRoot.setHTMLUnsafe()
TrustedScript
AsyncFunction()KonstruktorAsyncGeneratorFunction()Konstruktoreval()Element.setAttribute()(value-Argument)Element.setAttributeNS()(value-Argument)Function()KonstruktorGeneratorFunction()KonstruktorHTMLScriptElement.innerTextHTMLScriptElement.textContentHTMLScriptElement.textwindow.setTimeout()undWorkerGlobalScope.setTimeout()(code-Argument)window.setInterval()undWorkerGlobalScope.setInterval()(code-Argument)
TrustedScriptURL
Cross-Browser-Unterstützung für Trusted Types
Die Trusted Types API ist noch nicht in allen modernen Browsern verfügbar, jedoch heute überall einsetzbar dank der Kompatibilitätshilfen der W3C.
- Die volle Polyfill definiert die JavaScript-API, versucht die CSP aus dem aktuellen Dokument abzuleiten, und erzwingt die Nutzung von Trusted Types basierend auf der abgeleiteten CSP.
- Die nur API Polyfill definiert nur die JavaScript-API, und enthält nicht die Fähigkeit, die Nutzung von Trusted Types durch eine CSP zu erzwingen.
Neben diesen beiden Polyfills bietet die W3C eine sogenannte Tinyfill, die wir im Folgenden näher erläutern werden.
Beachten Sie, dass solange Sie Ihren Code in einem unterstützenden Browser mit aktivierter CSP-Durchsetzung getestet haben, Sie auf anderen Browsern nicht das volle Polyfill verwenden müssen — Sie können die gleichen Vorteile durch die API only Polyfill oder die Tinyfill erreichen.
Das liegt daran, dass die Durchsetzung Sie dazu zwingt, Ihren Code so zu refaktorisieren, dass alle Daten vor ihrer Übergabe an ein Injection Sink durch die Trusted Types API (und daher durch eine Bereinigungsfunktion) geleitet werden. Wenn Sie dann den refaktorierten Code in einem anderen Browser ohne Durchsetzung ausführen, wird er dennoch die gleichen Codepfade durchlaufen und Ihnen den gleichen Schutz bieten.
Trusted Types Tinyfill
In diesem Abschnitt betrachten wir, wie die Trusted Types Tinyfill eine Website schützen kann, obwohl sie überhaupt keine Unterstützung für Trusted Types hinzufügt.
Die Trusted Types Tinyfill ist nur dies:
if (typeof trustedTypes === "undefined")
trustedTypes = { createPolicy: (n, rules) => rules };
Sie bietet eine Implementierung von trustedTypes.createPolicy(), die einfach das policyOptions-Objekt zurückgibt, das ihr übergeben wurde. Das policyOptions-Objekt definiert Bereinigungsfunktionen für Daten, und diese Funktionen sollen Strings zurückgeben.
Mit dieser Tinyfill an Ort und Stelle, nehmen wir an, wir erstellen eine Policy:
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 ein Injection Sink übergeben werden, und wir können durchsetzen, dass das Sink einen Trusted Type statt eines Strings erhalten hat.
In Browsern, die Trusted Types nicht unterstützen, wird dieser Code ein Objekt mit einer createHTML()-Funktion zurückgeben, die ihre Eingabe bereinigt und diese als String zurückgibt. Der bereinigte String kann dann an ein 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.
So oder so erhält das Injection Sink bereinigte Daten, und da wir die Verwendung der Policy im unterstützenden Browser durchsetzen konnten, wissen wir, dass dieser Codepfad auch im nicht unterstützenden Browser durch die Bereinigungsfunktion geht.
Schnittstellen
TrustedHTML-
Repräsentiert einen String, der in ein Injection Sink eingefügt wird, das ihn als HTML rendert.
TrustedScript-
Repräsentiert einen String, der in ein Injection Sink eingefügt wird, das dazu führen könnte, dass das Skript ausgeführt wird.
TrustedScriptURL-
Repräsentiert einen String, der in ein Injection Sink eingefügt wird, das ihn als URL einer externen Skriptressource analysiert.
TrustedTypePolicy-
Definiert die Funktionen, die verwendet werden, um die oben genannten Trusted Type-Objekte zu erstellen.
TrustedTypePolicyFactory-
Erstellt Policy-Objekte und überprüft, ob Trusted Type-Objektinstanzen über eine der Policies erstellt wurden.
Erweiterungen für andere Schnittstellen
Window.trustedTypes-
Gibt das
TrustedTypePolicyFactory-Objekt zurück, das mit dem globalen Objekt im Haupt-Thread assoziiert ist. Dies ist der Einstiegspunkt für die Nutzung der API im Window-Thread. WorkerGlobalScope.trustedTypes.-
Gibt das
TrustedTypePolicyFactory-Objekt zurück, das mit dem globalen Objekt in einem Worker assoziiert ist.
Erweiterungen für 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 Policy-Namen anzugeben.
Content-Security-Policy-Schlüsselwörter
trusted-types-eval-
Erlaubt das Verwenden von
eval()und ähnlichen Funktionen, jedoch nur, wenn Trusted Types unterstützt und durchgesetzt werden.
Beispiele
Im folgenden Beispiel erstellen wir eine Policy, die TrustedHTML-Objekte mit TrustedTypePolicyFactory.createPolicy() erstellt. Wir können dann TrustedTypePolicy.createHTML() verwenden, um einen bereinigten HTML-String zu erstellen, der in das Dokument eingefügt werden soll.
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 Wege, Eingaben zu bereinigen im Artikel Verhindern von DOM-basierten Cross-Site-Scripting-Schwachstellen mit Trusted Types.
Spezifikationen
| Specification |
|---|
| Trusted Types> |