Signatur
Beschreibung
TrustedHTML gehört zur Trusted Types API, mit der sich DOM-basiertes Cross-Site-Scripting (XSS) verhindern lässt. Ein TrustedHTML-Objekt kapselt einen String, der zuvor eine selbst definierte Bereinigungsfunktion einer TrustedTypePolicy durchlaufen hat. Nur solche Objekte akzeptiert der Browser dann in gefährlichen „Injection-Senken“ wie Element.innerHTML, Element.outerHTML, insertAdjacentHTML(), document.write(), DOMParser.parseFromString() oder iframe.srcdoc.
Einen eigenen Konstruktor gibt es nicht. Objekte entstehen ausschließlich über policy.createHTML(input), wobei die Policy vorher mit trustedTypes.createPolicy(name, { createHTML }) angelegt wird. Wird die CSP-Direktive require-trusted-types-for 'script' gesetzt, lösen einfache Strings in diesen Senken einen TypeError aus. So muss jeder HTML-Fluss durch eine prüfbare, zentrale Stelle laufen.
Die Schnittstelle ist bewusst schlank gehalten. Sie bietet nur toString() und toJSON(), die beide den gekapselten String zurückgeben. Ob ein Wert tatsächlich vertrauenswürdig ist, prüfst du mit trustedTypes.isHTML(value). Ein instanceof-Vergleich reicht nicht, weil er sich über Realm-Grenzen hinweg anders verhält.
Rückgabewert
TrustedTypePolicy.prototype.createHTML() bzw. trustedTypes.emptyHTML geliefert. Instanzmethoden: toString() und toJSON() geben jeweils den bereinigten string zurück.Beispiele
Policy anlegen und TrustedHTML erzeugen
// Einfache Escape-Policy: Sonderzeichen unschädlich machen
const escapePolicy = trustedTypes.createPolicy('escape-html', {
createHTML: (input) => input
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
});
const userInput = '<img src=x onerror="alert(1)">';
const safe = escapePolicy.createHTML(userInput);
console.log(safe instanceof TrustedHTML);
console.log(trustedTypes.isHTML(safe));
document.querySelector('#kommentar').innerHTML = safe;
Bereinigung mit DOMPurify als Policy
// Voraussetzung: DOMPurify ist geladen
const sanitizer = trustedTypes.createPolicy('dompurify', {
createHTML: (dirty) => DOMPurify.sanitize(dirty)
});
const renderArticle = async (id) => {
const res = await fetch(`/api/articles/${id}`);
const { html } = await res.json();
document.querySelector('main').innerHTML = sanitizer.createHTML(html);
};
renderArticle(42);
toString(), toJSON() und emptyHTML
const policy = trustedTypes.createPolicy('demo', {
createHTML: (s) => s.trim()
});
const html = policy.createHTML(' <b>Hallo</b> ');
console.log(html.toString());
console.log(JSON.stringify({ markup: html }));
// Leeren Inhalt ohne Policy setzen
document.body.innerHTML = trustedTypes.emptyHTML;
console.log(trustedTypes.isHTML(trustedTypes.emptyHTML));
Erzwingen per CSP und Feature-Erkennung
// HTTP-Header:
// Content-Security-Policy: require-trusted-types-for 'script'; trusted-types dompurify
const setHTML = (el, markup) => {
if (window.trustedTypes?.createPolicy) {
const p = trustedTypes.createPolicy('fallback', { createHTML: (s) => s });
el.innerHTML = p.createHTML(markup);
} else {
el.innerHTML = markup; // Browser ohne Trusted Types
}
};
try {
document.body.innerHTML = '<p>roh</p>'; // bei aktiver CSP: TypeError
} catch (e) {
console.log(e.name);
}
// Wichtig · Fallstricke
- Sicherheit:
TrustedHTMList nur so sicher wie die FunktioncreateHTMLder Policy. Eine Policy wie(s) => shebelt den Schutz vollständig aus. Setze deshalb auf bewährte Bereinigungsbibliotheken wie DOMPurify und halte die Zahl der Policies klein. Mittrusted-types <namen>in der CSP legst du fest, welche Policies erlaubt sind. - Ohne die CSP-Direktive
require-trusted-types-for 'script'werden Trusted Types nicht erzwungen, und Strings funktionieren weiterhin. MitContent-Security-Policy-Report-Onlykannst du Verstöße zunächst nur melden lassen, statt sie zu blockieren. - Eine Policy namens
"default"wird automatisch auf jeden rohen String angewendet, der in eine Senke gelangt. Das ist praktisch für die Umstellung bestehender Anwendungen, aber auch riskant. - Es gibt keinen öffentlichen Konstruktor:
new TrustedHTML()wirft einenTypeError. createPolicy()wirft einen Fehler, wenn der Name laut CSP nicht erlaubt ist oder doppelt vergeben wird (außer bei'allow-duplicates').- Kompatibilität: Chromium-Browser unterstützen die API seit Version 83. Firefox und Safari haben sie erst kürzlich eingeführt. Prüfe die Unterstützung mit
window.trustedTypesoder nutze den offiziellen Polyfill (trusted-typesvon W3C/Google). In Node.js gibt es die API nicht.