ShadowRoot: setHTMLUnsafe() Methode
Baseline
2025
Newly available
Since September 2025, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.
Warnung: Diese Methode analysiert ihre Eingabe als HTML und schreibt das Ergebnis in das DOM. APIs wie diese sind als Injection-Sinks bekannt und potenziell ein Vektor für Cross-Site Scripting (XSS) Angriffe, wenn die Eingabe ursprünglich von einem Angreifer stammt.
Sie können dieses Risiko mindern, indem Sie immer TrustedHTML-Objekte anstelle von Zeichenfolgen übergeben und vertrauenswürdige Typen erzwingen.
Siehe Sicherheitsüberlegungen für weitere Informationen.
Hinweis:
ShadowRoot.setHTML() sollte fast immer anstelle dieser Methode verwendet werden – in Browsern, in denen sie unterstützt wird – da es immer XSS-unsichere HTML-Entitäten entfernt.
Die setHTMLUnsafe() Methode der ShadowRoot Schnittstelle kann verwendet werden, um HTML-Eingaben in ein DocumentFragment zu parsen, unerwünschte Elemente und Attribute optional zu filtern und damit den bestehenden Baum im Shadow DOM zu ersetzen.
Syntax
setHTMLUnsafe(input)
setHTMLUnsafe(input, options)
Parameter
input-
Eine Instanz von
TrustedHTMLoder eine Zeichenfolge, die das zu parsende HTML definiert. optionsOptional-
Ein Optionsobjekt mit den folgenden optionalen Parametern:
sanitizerOptional-
Ein
SanitizeroderSanitizerConfigObjekt, das definiert, welche Elemente der Eingabe erlaubt oder entfernt werden. Dies kann auch eine Zeichenfolge mit dem Wert"default"sein, die einenSanitizermit der Standardkonfiguration (XSS-sicher) anwendet. Wenn nicht angegeben, wird kein Sanitizer verwendet.Beachten Sie, dass im Allgemeinen ein
Sanitizereffizienter als einSanitizerConfigist, wenn die Konfiguration wiederverwendet werden soll.
Rückgabewert
Keiner (undefined).
Ausnahmen
TypeError-
Wird ausgelöst, wenn:
inputeine Zeichenfolge übergeben wird, wenn Trusted Types von einer CSP erzwungen werden und keine Standardrichtlinie definiert ist.options.sanitizerwird übergeben als:SanitizerConfig, die nicht gültig ist. Zum Beispiel eine Konfiguration, die sowohl "erlaubt" als auch "entfernt" Konfigurationseinstellungen enthält.- Zeichenfolge, die nicht den Wert
"default"hat. - Wert, der kein
Sanitizer,SanitizerConfigoder Zeichenfolge ist.
Beschreibung
Die setHTMLUnsafe() Methode kann verwendet werden, um eine Zeichenfolge von HTML zu analysieren, unerwünschte Elemente und Attribute optional zu filtern und sie zu verwenden, um das bestehende Shadow DOM zu ersetzen.
Im Gegensatz zu ShadowRoot.innerHTML werden declaration shadows in der Eingabe in das DOM geparst.
Wenn die HTML-Zeichenfolge mehr als eine declaration shadow in einem bestimmten Shadow-Host definiert, wird nur der erste ShadowRoot erstellt – nachfolgende Deklarationen werden als <template> Elemente innerhalb dieses Shadow-Roots geparst.
setHTMLUnsafe() führt standardmäßig keine Sanitization durch.
Wenn kein Sanitizer als Parameter übergeben wird, werden alle HTML-Entitäten in der Eingabe injiziert.
Sicherheitsüberlegungen
Das Suffix "Unsafe" im Methodennamen zeigt an, dass es nicht alle XSS-unsicheren HTML-Entitäten entfernt (im Gegensatz zu ShadowRoot.setHTML()).
Während es dies tun kann, wenn es mit einem geeigneten Sanitizer verwendet wird, müssen Sie keinen effektiven Sanitizer verwenden oder überhaupt einen Sanitizer verwenden!
Die Methode ist daher ein potenzieller Vektor für Cross-Site Scripting (XSS) Angriffe, bei denen potenziell unsichere Zeichenfolgen, die von einem Benutzer bereitgestellt werden, ohne vorherige Sanitization in das DOM injiziert werden.
Sie sollten dieses Risiko mindern, indem Sie immer TrustedHTML Objekte anstelle von Zeichenfolgen übergeben und vertrauenswürdige Typen mit der require-trusted-types-for CSP-Direktive erzwingen.
Dadurch wird sichergestellt, dass die Eingabe durch eine Transformationsfunktion geht, die die Chance hat, die Eingabe zu sanitizen, um potenziell gefährliches Markup (wie <script> Elemente und Ereignis-Handler-Attribute) zu entfernen, bevor sie injiziert wird.
Mit TrustedHTML ist es möglich, die Wirksamkeit des Sanitizationscodes an nur wenigen Stellen zu auditieren und zu überprüfen, anstatt über alle Ihre Injection-Sinks verstreut.
Sie sollten keinen Sanitizer an die Methode übergeben müssen, wenn Sie TrustedHTML verwenden.
Wenn Sie aus irgendeinem Grund TrustedHTML (oder noch besser, setHTML()) nicht verwenden können, ist die nächstsicherste Option, setHTMLUnsafe() mit dem XSS-sicheren Standard Sanitizer zu verwenden.
Wann sollte setHTMLUnsafe() verwendet werden?
setHTMLUnsafe() sollte nahezu nie verwendet werden, wenn ShadowRoot.setHTML() verfügbar ist, da es nur sehr wenige (wenn überhaupt) Fälle gibt, in denen nutzerbereitgestellte HTML-Eingaben XSS-unsichere Elemente enthalten müssen.
Nicht nur ist setHTML() sicher, sondern es vermeidet auch die Erwägung von Trusted Types.
Die Verwendung von setHTMLUnsafe() könnte angemessen sein, wenn:
-
Sie
setHTML()oder Trusted Types (aus welchem Grund auch immer) nicht verwenden können und das sicherste mögliche Filtern wünschen. In diesem Fall könnten SiesetHTMLUnsafe()mit dem StandardSanitizerverwenden, um alle XSS-unsicheren Elemente zu filtern. -
Sie
setHTML()nicht verwenden können und die Eingabe Deklarative Shadow Roots enthalten könnte, sodass SieShadowRoot.innerHTMLnicht verwenden können. -
Sie einen Randfall haben, bei dem Sie HTML-Eingaben zulassen müssen, die eine bekannte Menge unsicherer HTML-Entitäten enthalten.
Sie können
setHTML()in diesem Fall nicht verwenden, da es alle unsicheren Entitäten entfernt. Sie könntensetHTMLUnsafe()ohne einen Sanitizer oderinnerHTMLverwenden, aber das würde alle unsicheren Entitäten zulassen.Eine bessere Option hier ist,
setHTMLUnsafe()mit einem Sanitizer zu verwenden, der nur die gefährlichen Elemente und Attribute zulässt, die wir tatsächlich benötigen. Während dies immer noch unsicher ist, ist es sicherer, als alle zuzulassen.
Für den letzten Punkt, betrachten Sie eine Situation, in der Ihr Code davon abhängt, unsichere onclick-Handler verwenden zu können.
Der folgende Code zeigt die Wirkung der verschiedenen Methoden und Sanitizers in diesem Fall.
const shadow = document.querySelector("#host").shadowRoot;
const input = "<img src=x onclick=alert('onclick') onerror=alert('onerror')>";
// Safe - removes all XSS-unsafe entities.
shadow.setHTML(input);
// Removes no event handler attributes
shadow.setHTMLUnsafe(input);
shadow.innerHTML = input;
// Safe - removes all XSS-unsafe entities.
const configSafe = new Sanitizer();
shadow.setHTMLUnsafe(input, { sanitizer: configSafe });
// Removes all XSS-unsafe entities except `onclick`
const configLessSafe = new Sanitizer();
config.allowAttribute("onclick");
shadow.setHTMLUnsafe(input, { sanitizer: configLessSafe });
Beispiele
>setHTMLUnsafe() mit Trusted Types
Um das Risiko von XSS zu mindern, erstellen wir zuerst ein TrustedHTML-Objekt aus dem String, der das HTML enthält, und übergeben dann dieses Objekt an setHTMLUnsafe().
Da Trusted Types noch nicht in allen Browsern unterstützt werden, definieren wir das trusted types tinyfill.
Dies dient als transparenter Ersatz für die Trusted Types JavaScript API:
if (typeof trustedTypes === "undefined")
trustedTypes = { createPolicy: (n, rules) => rules };
Als nächstes erstellen wir eine TrustedTypePolicy, die ein createHTML() für die Transformation eines Eingabe-Strings in TrustedHTML Instanzen definiert.
Üblicherweise verwenden Implementierungen von createHTML() eine Bibliothek wie DOMPurify, um die Eingabe zu sanitizen, wie unten gezeigt:
const policy = trustedTypes.createPolicy("my-policy", {
createHTML: (input) => DOMPurify.sanitize(input),
});
Dann verwenden wir dieses policy-Objekt, um ein TrustedHTML-Objekt aus der potenziell unsicheren Eingabezeichenfolge zu erstellen:
// The potentially malicious string
const untrustedString = "abc <script>alert(1)<" + "/script> def";
// Create a TrustedHTML instance using the policy
const trustedHTML = policy.createHTML(untrustedString);
Jetzt, da wir trustedHTML haben, zeigt der Code unten, wie Sie es mit setHTMLUnsafe() verwenden können.
Zuerst erstellen wir den ShadowRoot, den wir anvisieren möchten.
Dies könnte programmgesteuert mit Element.attachShadow() erstellt werden, aber für dieses Beispiel erstellen wir die Wurzel deklarativ.
<div id="host">
<template shadowrootmode="open">
<span>A span element in the shadow DOM</span>
</template>
</div>
Dann erhalten wir ein Handle zum Shadow-Root vom #host Element und rufen setHTMLUnsafe() auf.
Da die Eingabe durch die Transformationsfunktion gegangen ist, übergeben wir keinen Sanitizer an die Methode.
const shadow = document.querySelector("#host").shadowRoot;
// setHTMLUnsafe() with no sanitizer (no filtering)
shadow.setHTMLUnsafe(trustedHTML);
Verwendung von setHTMLUnsafe() ohne Trusted Types
Dieses Beispiel demonstriert den Fall, in dem keine Trusted Types verwendet werden, sodass wir Sanitizer-Argumente übergeben werden.
Der Code erstellt zuerst einen untrusted String und zeigt eine Reihe von Wegen, auf denen ein Sanitizer an die Methode übergeben werden kann.
// The potentially malicious string
const untrustedString = "abc <script>alert(1)<" + "/script> def";
// Get the shadow root element
const shadow = document.querySelector("#host").shadowRoot;
// Define custom Sanitizer and use in setHTMLUnsafe()
// This allows only elements: div, p, button, script
const sanitizer1 = new Sanitizer({
elements: ["div", "p", "button", "script"],
});
shadow.setHTMLUnsafe(untrustedString, { sanitizer: sanitizer1 });
// Define custom SanitizerConfig within setHTMLUnsafe()
// Removes the <script> element but allows other potentially unsafe entities.
shadow.setHTMLUnsafe(untrustedString, {
sanitizer: { removeElements: ["script"] },
});
setHTMLUnsafe() Live-Beispiel
Dieses Beispiel bietet eine "Live"-Demonstration der Methode, wenn sie mit verschiedenen Sanitizers aufgerufen wird.
Der Code definiert Schaltflächen, die Sie anklicken können, um eine Zeichenfolge von HTML einzufügen.
Eine Schaltfläche fügt das HTML ohne jegliche Sanitization ein, und die zweite verwendet einen benutzerdefinierten Sanitizer, der <script>-Elemente, aber keine anderen unsicheren Elemente zulässt.
Die Originalzeichenfolge und das injizierte HTML werden geloggt, sodass Sie die Ergebnisse in jedem Fall inspizieren können.
Hinweis: Da wir zeigen möchten, wie das Sanitizer-Argument verwendet wird, injiziert der folgende Code eine Zeichenfolge anstelle eines Trusted Types. Sie sollten dies im produktiven Code nicht tun.
HTML
Das HTML definiert zwei <button> Elemente zum Einfügen des HTML ohne Sanitizer und mit einem benutzerdefinierten Sanitizer (jeweils), eine weitere Schaltfläche zum Zurücksetzen des Beispiels und ein <div>, das den deklarativen Shadow-Root enthält.
<button id="buttonNoSanitizer" type="button">None</button>
<button id="buttonAllowScript" type="button">allowScript</button>
<button id="reload" type="button">Reload</button>
<div id="host">
<template shadowrootmode="open">
<span>I am in the shadow DOM </span>
</template>
</div>
JavaScript
Zuerst definieren wir den Handler für die Reload-Schaltfläche.
const reload = document.querySelector("#reload");
reload.addEventListener("click", () => document.location.reload());
Dann definieren wir die Eingabezeichenfolge, um sie in den Shadow-Root einzufügen, was in allen Fällen gleich sein wird.
Dies enthält das <script> Element und den onclick-Handler, die beide als XSS-unsicher gelten.
Wir bekommen auch die Variable shadow, die unser Handle zum Shadow-Root ist.
// Define unsafe string of HTML
const unsanitizedString = `
<div>
<p>Paragraph to inject into shadow DOM.
<button onclick="alert('You clicked the button!')">Click me</button>
</p>
<script src="path/to/a/module.js" type="module"><\/script>
<p data-id="123">Para with <code>data-</code> attribute</p>
</div>
`;
const shadow = document.querySelector("#host").shadowRoot;
Als nächstes definieren wir den Klick-Handler für die Schaltfläche, die den Shadow-Root mit setHTMLUnsafe() ohne einen Sanitizer zu übergeben, setzt.
Da kein Sanitizer vorhanden ist, erwarten wir, dass das injizierte HTML der Eingabezeichenfolge entspricht.
const buttonNoSanitizer = document.querySelector("#buttonNoSanitizer");
buttonNoSanitizer.addEventListener("click", () => {
// Set the content of the element with no sanitizer
shadow.setHTMLUnsafe(unsanitizedString);
// Log HTML before sanitization and after being injected
logElement.textContent = "No sanitizer\n\n";
log(`\nunsanitized: ${unsanitizedString}`);
log(`\n\nsanitized: ${shadow.innerHTML}`);
});
Der nächste Klick-Handler setzt das Ziel-HTML mit einem benutzerdefinierten Sanitizer, der nur <div>, <p> und <script> Elemente erlaubt.
const allowScriptButton = document.querySelector("#buttonAllowScript");
allowScriptButton.addEventListener("click", () => {
// Set the content of the element using a custom sanitizer
const sanitizer1 = new Sanitizer({
elements: ["div", "p", "script"],
});
shadow.setHTMLUnsafe(unsanitizedString, { sanitizer: sanitizer1 });
// Log HTML before sanitization and after being injected
logElement.textContent = "Sanitizer: {elements: ['div', 'p', 'script']}\n";
log(`\n\nunsanitized: ${unsanitizedString}`);
log(`\nsanitized: ${shadow.innerHTML}`);
});
Ergebnisse
Klicken Sie auf die Schaltflächen "None" und "allowScript", um die Effekte ohne einen Sanitizer bzw. mit einem benutzerdefinierten Sanitizer zu sehen.
Wenn Sie auf die Schaltfläche "None" klicken, sollten Sie feststellen, dass die Eingabe und Ausgabe identisch sind, da kein Sanitizer angewendet wird.
Wenn Sie auf die Schaltfläche "allowScript" klicken, ist das <script> Element weiterhin vorhanden, aber das <button> Element wird entfernt.
Mit diesem Ansatz können Sie sicher HTML erstellen, aber Sie sind nicht dazu gezwungen.
Spezifikationen
| Specification |
|---|
| HTML> # dom-shadowroot-sethtmlunsafe> |