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:

JavaScript ohne-trusted-types.js
// Funktioniert — und ist verwundbar, wenn user-input nicht sanitisiert wurde
element.innerHTML = userInput;

Mit aktivierter Trusted-Types-Policy:

JavaScript mit-trusted-types.js
// 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.innerHTML
  • element.outerHTML
  • element.insertAdjacentHTML(...)
  • document.write(...), document.writeln(...)
  • iframe.srcdoc
  • range.createContextualFragment(...)
  • DOMParser.parseFromString(..., 'text/html')

TrustedScript-Sinks:

  • eval(...)
  • Function(...)
  • setTimeout('code', ...) mit String-Argument
  • setInterval('code', ...) mit String-Argument
  • script.text, script.innerText, script.textContent

TrustedScriptURL-Sinks:

  • script.src
  • worker = 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-src abgedeckt.
  • location.href mit javascript:-URLs — durch CSP-script-src abgedeckt.

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:

HTTP csp-trusted-types.http
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types myApp dompurify-policy default

Bedeutung:

  • 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:

JavaScript policy-registrieren.js
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.

JavaScript default-policy.js
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.

HTTP tt-report-only.http
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-to csp-endpoint

Browser 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:

JavaScript default-policy-migration.js
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:

JavaScript explicit-policy.js
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:

JavaScript dompurify-tt.js
// 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

/ Weiter

Zurück zu XSS & Content Injection

Zur Übersicht