Trusted Types sind die strukturelle Antwort auf DOM-XSS, die andere Schutz-Mechanismen nicht liefern können. Anstatt zu hoffen, dass kein Entwickler-Code aus Versehen einen User-String per innerHTML rendert, sagt der Browser: „innerHTML akzeptiert nur noch Werte, die explizit als sicher markiert sind." Wer einen nackten String übergibt, bekommt einen TypeError. Damit verschiebt sich DOM-Sicherheit von „hoffen, dass niemand fehler macht" zu „der Browser zwingt zur korrekten Verarbeitung".
Das Problem, das Trusted Types löst
Klassische XSS-Verteidigung sagt: alle User-Input vor innerHTML sanitisieren. In der Theorie sauber, in der Praxis fragil — jede einzelne Stelle im Code, die innerHTML nutzt, muss korrekt schützen. Eine vergessene Stelle reicht für die XSS-Lücke.
Trusted Types dreht das Modell um: gefährliche Sinks akzeptieren keine nackten Strings mehr. Stattdessen müssen Werte einen speziellen Typ haben — TrustedHTML, TrustedScript, TrustedScriptURL. Diese Typen werden nur von einer explizit definierten Policy erzeugt. Der Browser erzwingt das.
Klassisches DOM-XSS-Pattern, vor Trusted Types:
// Funktioniert — und ist verwundbar, wenn user-input nicht sanitisiert wurde
element.innerHTML = userInput;Mit aktivierter Trusted-Types-Policy:
// Browser wirft TypeError: 'innerHTML' requires 'TrustedHTML' assignment
element.innerHTML = userInput;
// So geht es richtig
const policy = trustedTypes.createPolicy('myApp', {
createHTML: (input) => DOMPurify.sanitize(input),
});
element.innerHTML = policy.createHTML(userInput);Der Browser lehnt den nackten String ab. Die einzige Möglichkeit, etwas in innerHTML zu schreiben, ist durch eine explizit definierte Policy, die du in deiner Anwendung registriert hast — und die idealerweise Sanitization implementiert.
Welche Sinks sind betroffen?
Trusted Types schützen alle bekannten DOM-XSS-Sinks. Die wichtigsten:
TrustedHTML-Sinks:
element.innerHTMLelement.outerHTMLelement.insertAdjacentHTML(...)document.write(...),document.writeln(...)iframe.srcdocrange.createContextualFragment(...)DOMParser.parseFromString(..., 'text/html')
TrustedScript-Sinks:
eval(...)Function(...)setTimeout('code', ...)mit String-ArgumentsetInterval('code', ...)mit String-Argumentscript.text,script.innerText,script.textContent
TrustedScriptURL-Sinks:
script.srcworker = new Worker(url)importScripts(...)
Was NICHT von Trusted Types abgedeckt ist:
element.setAttribute(...)mit beliebigem Attribut — funktioniert ohne Trusted Types, ist aber durch CSP-script-srcabgedeckt.location.hrefmitjavascript:-URLs — durch CSP-script-srcabgedeckt.
Trusted Types fokussieren auf die String-zu-Code-Sinks, die historisch die häufigsten DOM-XSS-Vektoren waren.
Wie man Trusted Types aktiviert
Trusted Types werden über die Content Security Policy aktiviert:
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types myApp dompurify-policy defaultBedeutung:
require-trusted-types-for 'script'— alle skript-relevanten DOM-Sinks verlangen Trusted Types.trusted-types myApp dompurify-policy default— Liste der erlaubten Policy-Namen, die in der Anwendung registriert werden dürfen.
Policy registrieren:
if (window.trustedTypes && window.trustedTypes.createPolicy) {
const policy = trustedTypes.createPolicy('myApp', {
createHTML: (input) => DOMPurify.sanitize(input),
createScript: (input) => {
// Validiere, dass nur erwartete Skripte durchkommen
if (input === 'allowed-inline-script-content') return input;
throw new Error('Disallowed script content');
},
createScriptURL: (input) => {
// URL muss aus eigener Origin oder Whitelist kommen
const url = new URL(input, location.href);
if (url.origin === location.origin) return input;
throw new Error('Disallowed script URL');
},
});
// Verwenden
element.innerHTML = policy.createHTML(userInput);
}Default-Policy als Migrations-Hilfe:
Eine Policy mit dem Namen default wird automatisch für alle Strings angewendet, die einem Trusted-Types-Sink übergeben werden — ohne dass der Code explizit policy.createHTML(...) aufruft.
trustedTypes.createPolicy('default', {
createHTML: (input) => DOMPurify.sanitize(input),
});
// Funktioniert weiter — Default-Policy wird automatisch angewendet
element.innerHTML = userInput;Damit kann man bestehende Anwendungen schrittweise migrieren, ohne jeden innerHTML-Aufruf umschreiben zu müssen. Default-Policy sollte sanitiseren, sonst hat man keinen Schutz mehr — es ist ein Migrations-Werkzeug, kein Endziel.
Browser-Unterstützung und Polyfill
Stand 2026:
- Chrome / Edge / Opera — seit Chrome 83 (2020) voll unterstützt.
- Firefox — schrittweise Implementierung, Stand 2026 weitgehend kompatibel.
- Safari — Implementierung in Arbeit; Stand 2026 noch ohne volle Unterstützung.
Für Browser ohne native Unterstützung gibt es das w3c/trusted-types/polyfill. Funktional, aber mit Performance-Overhead — empfohlen vor allem, um Browser-übergreifend zu testen, in Produktion meist nur dort sinnvoll, wo Safari-Anteil hoch ist.
Wichtige Limitierung: Trusted Types sind als opt-in über CSP aktiv. Browser, die TT nicht kennen, ignorieren die CSP-Direktive — die Anwendung läuft weiter, aber ohne TT-Schutz. Für Safari-Nutzer:innen wirkt der Schutz also derzeit nicht — die CSP-Schicht ohne TT muss ihn weiter abdecken.
Migration in bestehenden Anwendungen
Wie führt man Trusted Types in einer bestehenden Anwendung ein?
Phase 1 — Report-Only-Modus.
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-to csp-endpointBrowser meldet Violations, blockt aber nichts. Du sammelst Daten: welche Stellen in deinem Code übergeben String-Werte an Trusted-Types-Sinks?
Phase 2 — Default-Policy mit Sanitization.
Registriere eine Default-Policy, die alle nicht-explizit gehärteten Stellen durch DOMPurify schickt:
trustedTypes.createPolicy('default', {
createHTML: (input) => DOMPurify.sanitize(input),
// Default-Policy soll nicht still alles erlauben — bewusst limitieren
createScript: () => {
throw new Error('Default policy disallows createScript');
},
createScriptURL: () => {
throw new Error('Default policy disallows createScriptURL');
},
});Damit ist deine App rückwärts-kompatibel und gleichzeitig gehärtet. Bestehende innerHTML-Aufrufe laufen durch Sanitization; eval-ähnliche Sinks scheitern.
Phase 3 — Schrittweise explizite Policies.
Für legitime Use-Cases (z. B. ein Code-Editor, der bewusst Code rendern muss) eigene Policies definieren und im Code ausdrücklich aufrufen:
const codeEditorPolicy = trustedTypes.createPolicy('code-editor', {
createHTML: (input) => {
// Code-Editor-spezifische Sanitization
return CodeMirror.highlight(input);
},
});
codeView.innerHTML = codeEditorPolicy.createHTML(editorContent);Phase 4 — Enforce.
Wenn die Reports ruhig sind, wechseln auf erzwungene CSP. Default-Policy mit Sanitization weiter aktiv, explizite Policies pro Use-Case definiert.
Framework-Unterstützung
Mehrere Frameworks haben eingebaute Trusted-Types-Unterstützung:
Angular — seit Version 11 (2020) eingebaute TT-Unterstützung. [innerHTML]-Bindings, die durch den DomSanitizer laufen, sind automatisch TT-konform. Aktivierung über die App-Konfiguration.
Lit / lit-html — eingebaute Unterstützung seit 2021.
DOMPurify — die populärste HTML-Sanitization-Library hat seit Version 2.0 native Trusted-Types-Unterstützung:
// DOMPurify gibt direkt TrustedHTML zurück, wenn TT aktiv ist
element.innerHTML = DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: true });React — eingebaute TT-Unterstützung in den Renderer-Internals; dangerouslySetInnerHTML ist mit TT kompatibel. Wer Default-Policy mit Sanitization registriert, härtet automatisch alle React-dangerouslySetInnerHTML-Aufrufe.
Vue — keine native TT-Integration; v-html-Bindings müssen über eine Default-Policy mit Sanitization geschützt werden.
Svelte — keine native Integration; {@html} durch Default-Policy schützen.
Faustregel: React und Angular sind bei TT-Migration einfacher, weil sie ohnehin Sanitization-Patterns haben. Vue und Svelte verlangen eine Default-Policy als Brücke.
Reale Wirkung
Eine sehr aussagekräftige Statistik aus der Google-Forschung (2020):
Über 60 Prozent aller XSS-Bugs, die in Googles eigenen Sicherheits-Reviews gefunden wurden, wären durch Trusted Types strukturell verhindert worden. Genau wegen dieser Wirkung hat Google den Standard maßgeblich entwickelt und intern in vielen Produkten ausgerollt.
In der Praxis:
- Google Photos, Gmail, YouTube nutzen Trusted Types in mehreren Komponenten.
- GitHub hat 2021/22 schrittweise Migration begonnen.
- Cloudflare Dashboard hat TT eingeführt.
- Diverse Banking- und Healthcare-Apps mit hohen Sicherheits-Anforderungen.
Für eine neue Anwendung ist die Empfehlung klar: von Anfang an Trusted Types nutzen. Die Migrations-Schmerzen späterer Apps entfallen, und die Architektur ist von Beginn an DOM-XSS-resistent.
Stolpersteine
1. Drittanbieter-Libraries.
Externe Libraries (Charts, Editoren, Widgets) nutzen oft innerHTML. Wenn sie keine TT-Unterstützung haben, brechen sie unter strikter Policy. Lösungen:
- Library auf TT-fähige Version aktualisieren (wenn verfügbar).
- Library in einem separaten iframe isolieren, wo TT nicht erzwungen ist.
- Default-Policy mit Sanitization registrieren — die Library-Aufrufe laufen durch.
2. Inline-<script>-Tags.
Trusted Types greifen für script.text und script.src. Statisch hardcodierte <script>...</script>-Tags im HTML laufen ohne Konflikt; dynamisch erzeugte Skript-Tags brauchen aber TT.
3. eval() in Legacy-Code.
Wenn alter Code eval nutzt, scheitert er hart unter TT. Manuelle Code-Reviews und Refactoring nötig.
4. CSP-Interaktion.
TT funktioniert nur, wenn die CSP require-trusted-types-for 'script' enthält. Manche WAFs oder Reverse-Proxies modifizieren CSP-Header — prüfen, dass die TT-Direktive am Browser ankommt.
5. Safari fehlt noch. Solange Safari TT nicht voll unterstützt, ist der Schutz Browser-spezifisch. Für Safari-Nutzer:innen wirken nur die anderen Schutz-Layer (CSP-Nonces, Sanitization).
Besonderheiten
Trusted Types von Google 2018 vorgeschlagen
Krzysztof Kotowicz und das Google-Security-Team haben die Spezifikation 2018 vorgeschlagen, als Reaktion auf die Beobachtung, dass DOM-XSS in Google-Produkten trotz Sanitization-Disziplin immer wiederkam. Die Idee: nicht hoffen, dass Entwickler sanitisieren, sondern den Browser dazu zwingen.
DOMPurify ist die Standard-Sanitization-Library für TT
DOMPurify hat seit 2.0 die RETURN_TRUSTED_TYPE-Option. Die Library wird von Mario Heiderich und Team gepflegt, ist Industrie-Standard für Browser-HTML-Sanitization und unterstützt TT direkt.
Built-in HTML Sanitizer API kommt — irgendwann
Das W3C arbeitet seit Jahren an einer eingebauten Sanitizer-API. Chrome hat eine Vorschau-Implementierung, andere Browser hinken hinterher. Wenn etabliert, würde sie Trusted Types ergänzen — Browser liefert Sanitization out of the box. Bis dahin bleibt DOMPurify die Standard-Antwort.
Trusted Types und Frameworks-Performance
Manche Bedenken: schadet TT der Performance? Die Antwort: minimal. Policy-Aufrufe sind synchrone Funktionen — der Overhead pro Aufruf ist mikroskopisch. Wenn die Default-Policy DOMPurify aufruft, kommt der Sanitization-Overhead dazu (für komplexe HTML einige Millisekunden) — der war ohnehin nötig.
Trusted Types vs. CSP — wer macht was?
Trusted Types schützen DOM-Sinks — also wo String zu Code wird. CSP schützt Skript-Quellen — also welche Skripte überhaupt geladen werden dürfen. Beide ergänzen sich, ersetzen sich nicht. Eine moderne XSS-resistente App hat beides aktiv.
Default-Policy als Sicherheits-Falle
Eine Default-Policy, die alle Strings durchwinkt (createHTML: (input) => input), ist schlechter als gar keine TT. Sie deaktiviert den Schutz, lässt aber die Compliance-Häkchen aktiv. Default-Policy muss sanitisieren, sonst nicht aktivieren.
Google Forschungs-Studie zur Wirksamkeit
Eine interne Google-Studie (2020 veröffentlicht) wertete historische XSS-Bugs aus und schätzte, dass 60–70 % durch Trusted Types verhindert worden wären. Plus: TT macht Sicherheits-Reviews schneller, weil ein einfacher Grep nach „createHTML" alle Roh-Insertion-Stellen findet.
Weiterführende Ressourcen
Externe Quellen
- W3C — Trusted Types Spezifikation
- web.dev — Prevent DOM XSS with Trusted Types
- W3C Trusted Types GitHub
- Trusted Types Polyfill
- DOMPurify
- Angular Security Guide
- Sanitizer API (in Entwicklung)
- Chromium — Trusted Types Implementation