Trusted Types API im Detail: DOM XSS strukturell verhindern
AI generated
JS
() =>
JavaScript · Web Security · DOM XSS
Trusted Types API im Detail
DOM XSS auf Typebene ausschließen

DOM basiertes Cross Site Scripting entsteht meist nicht durch fehlende serverseitige Filterung, sondern durch unsichere Zuweisungen an innerHTML, document.write oder eval mitten im Frontend Code. Die Trusted Types API schließt diese Lücke strukturell, indem der Browser gefährliche Zuweisungen an DOM Sinks nur noch akzeptiert, wenn der Wert vorher durch eine definierte Policy in einen speziellen Typ umgewandelt wurde.

17 Min. Lesezeit TrustedHTML · TrustedScript · TrustedScriptURL Chrome · Edge · Firefox (Flag)

1. Warum DOM XSS trotz CSP weiter möglich ist

Eine Content Security Policy schützt zuverlässig davor, dass fremde Skripte von falschen Quellen ausgeführt werden, verhindert aber nicht, dass eigener, an sich vertrauenswürdiger Code eine unsichere Zeichenkette an innerHTML oder document.write übergibt. Genau hier setzt die Trusted Types API an: Sie behandelt nicht die Herkunft eines Skripts, sondern den Datenfluss innerhalb der Anwendung selbst, an der Stelle, wo eine Zeichenkette zu HTML, Skript oder URL wird.

Ein typisches Beispiel: Eine Suchfunktion baut das Ergebnis Markup per Template Literal zusammen und weist es direkt element.innerHTML zu. Enthält der Suchbegriff ein Skript Tag, das nicht korrekt escaped wurde, führt der Browser es aus, ganz ohne fremde Domain, ganz ohne Content Security Policy Verletzung im klassischen Sinn. Die Trusted Types API verhindert genau diesen Fall, indem innerHTML nach Aktivierung nur noch spezielle TrustedHTML Objekte akzeptiert, keine rohen Strings mehr.

Statistisch gesehen entstehen DOM basierte Cross Site Scripting Schwachstellen in der Praxis häufiger durch harmlos wirkenden, eigenen Anwendungscode als durch klassische Server seitige Injection Lücken. Genau diese Beobachtung war die ursprüngliche Motivation von Google, die Trusted Types API zu entwickeln und in Chrome zu implementieren.

2. Trusted Types aktivieren und require-trusted-types-for

Aktiviert wird die Trusted Types API über die Content Security Policy Direktive require-trusted-types-for 'script'. Ab diesem Moment wirft der Browser eine TypeError Exception, sobald ein roher String an einen der geschützten DOM Sinks übergeben wird, statt ihn stillschweigend zu akzeptieren. Diese harte Fehlermeldung ist gewollt: Sie zwingt Entwickler, jede Zuweisung explizit über eine Policy laufen zu lassen, statt implizite Annahmen über die Sicherheit eines Strings zu treffen.

Zusätzlich kann trusted-types als eigene Direktive festlegen, welche Policy Namen überhaupt erlaubt sind, etwa trusted-types default myapp-sanitizer 'allow-duplicates'. Ohne diese Einschränkung könnte theoretisch jeder Code im Dokument beliebig viele Policies mit beliebigen Namen registrieren, was die Kontrolle über den Datenfluss wieder aufweichen würde. Die Kombination aus require-trusted-types-for und trusted-types bildet damit ein zweistufiges Sicherheitsnetz.


Content-Security-Policy:
  require-trusted-types-for 'script';
  trusted-types default myapp-sanitizer 'allow-duplicates';

3. Policies erstellen: createHTML, createScript, createScriptURL

Eine Trusted Types Policy wird über trustedTypes.createPolicy(name, rules) registriert und definiert drei mögliche Transformationsfunktionen: createHTML für TrustedHTML, createScript für TrustedScript und createScriptURL für TrustedScriptURL. Jede dieser Funktionen nimmt einen rohen String entgegen und muss eine bereinigte Version zurückgeben, bevor der Browser sie an einem geschützten Sink akzeptiert.

Der entscheidende Vorteil gegenüber einer manuellen Sanitizer Funktion ist die Erzwingbarkeit: Sobald require-trusted-types-for 'script' aktiv ist, kann kein Code mehr an der Policy vorbei direkt Strings zuweisen, weil der Browser selbst die Typprüfung durchsetzt. Ein vergessener Aufruf der Sanitizer Funktion an einer einzelnen Codestelle führt nicht mehr zu einer stillen Sicherheitslücke, sondern zu einer sofortigen Exception, die in Tests oder im Betrieb sichtbar wird.


// Register a Trusted Types policy with DOMPurify as sanitizer
const sanitizerPolicy = trustedTypes.createPolicy('myapp-sanitizer', {
  createHTML: (input) => DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: false }),
  createScriptURL: (input) => {
    const allowed = ['https://cdn.mironsoft.de/'];
    if (!allowed.some((prefix) => input.startsWith(prefix))) {
      throw new TypeError('Script URL not allowed: ' + input);
    }
    return input;
  },
});

// Now innerHTML only accepts TrustedHTML produced by the policy
function renderSearchResults(container, rawMarkup) {
  container.innerHTML = sanitizerPolicy.createHTML(rawMarkup);
}

4. Die default Policy für Legacy Code und Drittbibliotheken

Wird eine Policy mit dem reservierten Namen default registriert, greift sie automatisch für jeden String, der ohne explizite Policy an einen geschützten Sink übergeben wird. Das ist besonders wertvoll für große Codebasen, in denen nicht jede einzelne Zuweisung sofort auf eine explizite Policy umgestellt werden kann. Die default Policy fungiert dann als Sicherheitsnetz, das jede unbehandelte Zuweisung durch dieselbe Sanitizer Logik schickt, bevor sie überhaupt fehlschlägt.

Wichtig ist, die default Policy nicht als dauerhafte Lösung zu missverstehen, sondern als Migrationswerkzeug. Wer sich langfristig nur auf die default Policy verlässt, verliert die Möglichkeit, unterschiedliche Sicherheitsanforderungen für unterschiedliche Datenflüsse abzubilden, etwa strengere Regeln für Nutzereingaben gegenüber serverseitig generiertem Markup. Der empfohlene Weg ist, kritische Codepfade schrittweise auf benannte, spezifische Policies umzustellen und die default Policy nur für Alt Code und Drittbibliotheken zu behalten.


// Fallback policy for legacy code paths not yet migrated
if (window.trustedTypes && trustedTypes.createPolicy) {
  trustedTypes.createPolicy('default', {
    createHTML: (input) => {
      console.warn('Legacy innerHTML assignment sanitized via default policy');
      return DOMPurify.sanitize(input);
    },
  });
}

Zusätzlich zur eigentlichen Sanitizer Logik lohnt es sich, jede Policy mit Logging zu versehen, das protokolliert, wie oft und an welcher Stelle im Code die Policy tatsächlich durchlaufen wird. Diese Telemetrie erleichtert später die Entscheidung, welche Codepfade von der default Policy auf eine spezifischere, benannte Policy migriert werden sollten.

5. Geschützte DOM Sinks im Überblick

Die Trusted Types API schützt eine feste Liste bekannter DOM Sinks, die historisch für die meisten DOM XSS Schwachstellen verantwortlich sind. Dazu gehören Element.innerHTML, Element.outerHTML, document.write, document.writeln, das src Attribut von script Elementen sowie Funktionen wie eval und setTimeout mit String Argument, sofern require-trusted-types-for 'script' aktiv ist.

Nicht abgedeckt sind DOM APIs, die von Natur aus sicher sind, etwa textContent oder createElement gefolgt von setAttribute für nicht kritische Attribute. Diese Unterscheidung ist wichtig: Die Trusted Types API ersetzt nicht generelles sicheres Coding, sondern erzwingt es an genau den Stellen, an denen ein String faktisch als HTML, Skript oder URL interpretiert wird. Für alle anderen DOM Operationen bleibt normales JavaScript ohne zusätzliche Policy nutzbar.

6. Violation Reporting und schrittweise Migration

Analog zur Content Security Policy unterstützt auch die Trusted Types API einen Report Only Modus über Content-Security-Policy-Report-Only: require-trusted-types-for 'script'. In diesem Modus wirft der Browser keine Exception, meldet aber jede Verletzung an den konfigurierten Reporting Endpunkt. Das erlaubt, den gesamten Codepfad einer Anwendung über einen längeren Zeitraum zu beobachten, bevor der harte Enforcement Modus aktiviert wird.

In der Praxis empfiehlt sich eine Migration in drei Phasen: Erst Report Only mit umfassendem Logging, dann eine default Policy als breites Sicherheitsnetz, und zuletzt die schrittweise Ablösung durch benannte, spezifische Policies für jeden kritischen Datenfluss. Diese Reihenfolge verhindert, dass eine große Legacy Codebasis beim ersten Enforcement sofort mit hunderten Fehlern ausfällt.

7. Trusted Types in Frameworks und Bibliotheken

Moderne Frameworks wie Angular unterstützen Trusted Types bereits nativ und erzeugen intern TrustedHTML Objekte für Direktiven wie [innerHTML]. React arbeitet standardmäßig ohnehin mit escaped Strings über JSX, benötigt Trusted Types also seltener direkt, außer bei explizitem dangerouslySetInnerHTML. Für diesen Fall lässt sich eine dedizierte Policy registrieren, die React Markup vor der Zuweisung durch DOMPurify schickt.

Bibliotheken ohne native Unterstützung, etwa ältere jQuery Plugins, die direkt mit .html() arbeiten, benötigen entweder eine default Policy oder ein gezieltes Wrapping der betroffenen Aufrufe. Wichtig ist, vor der Migration zu prüfen, ob die verwendete Bibliothek überhaupt Trusted Types kompatibel ist, da einige ältere Pakete den Einsatz von eval in einer Weise nutzen, die auch mit Sanitizer Policy nicht sauber lösbar ist und einen Bibliothekswechsel erfordert.

8. Typische Fehler und Fallstricke

Der häufigste Fehler ist, die default Policy dauerhaft als einzige Lösung zu betreiben, ohne kritische Datenflüsse jemals auf spezifische Policies umzustellen. Das führt dazu, dass Nutzereingaben und serverseitig generiertes Markup mit derselben, oft zu freizügigen Sanitizer Logik behandelt werden. Ein zweiter Fehler ist, die Sanitizer Funktion einer Policy selbst unsicher zu implementieren, etwa mit einer eigenen Regex basierten Bereinigung statt einer geprüften Bibliothek wie DOMPurify.

Ein dritter Fehler betrifft Browser Kompatibilität: Firefox und Safari unterstützen die Trusted Types API nur eingeschränkt oder gar nicht, weshalb die Anwendung ohne Trusted Types Unterstützung trotzdem funktionieren muss. Ein Feature Detection Check über window.trustedTypes vor der Policy Registrierung verhindert, dass die Anwendung in nicht unterstützten Browsern mit einer Exception abstürzt.


// Feature detection before registering a policy — required for Firefox/Safari
if (window.trustedTypes && trustedTypes.createPolicy) {
  const policy = trustedTypes.createPolicy('myapp-sanitizer', {
    createHTML: (input) => DOMPurify.sanitize(input),
  });
  window.__cspPolicy = policy;
} else {
  // Fallback: manual sanitization without native enforcement
  window.__cspPolicy = { createHTML: (input) => DOMPurify.sanitize(input) };
}

// Usage stays identical regardless of native support
function safeRender(container, rawMarkup) {
  container.innerHTML = window.__cspPolicy.createHTML(rawMarkup);
}

Diese Art der Feature Detection sollte zentral an einem einzigen Ort im Bootstrap Code der Anwendung erfolgen, nicht verstreut an jeder einzelnen Stelle, an der eine Policy benötigt wird. So bleibt die Kompatibilitätslogik wartbar, auch wenn sich der Browser Support für die Trusted Types API in Zukunft ändert.

9. Trusted Types im Vergleich zu anderen Schutzmaßnahmen

Trusted Types ergänzt, ersetzt aber nicht andere Sicherheitsmaßnahmen gegen Cross Site Scripting. Die folgende Tabelle ordnet die Trusted Types API im Vergleich zu klassischer Sanitisierung und einer Content Security Policy ein.

Maßnahme Schützt vor Durchsetzung Grenzen
Manuelle Sanitisierung Bekannte HTML Injection Muster Konvention, keine Erzwingung Vergessene Aufrufe bleiben unsichtbar
Content Security Policy Fremde Skript Quellen, Inline Skripte Browser Enforcement Schützt nicht vor eigenem unsicherem DOM Code
Trusted Types API DOM basiertes XSS über innerHTML, eval, Script Src Browser Enforcement auf Typebene Eingeschränkte Browser Unterstützung

In der Praxis ergänzen sich alle drei Maßnahmen: Eine Content Security Policy blockiert fremde Quellen, die Trusted Types API erzwingt sichere Umwandlung an geschützten Sinks, und manuelle Sanitisierung mit einer geprüften Bibliothek liefert die eigentliche Bereinigungslogik innerhalb der Policy. Keine der drei Maßnahmen ersetzt die anderen vollständig.

Mironsoft

DOM Sicherheit, Trusted Types Migration und Sanitizer Audits

DOM basiertes Cross Site Scripting strukturell ausschließen?

Wir identifizieren gefährliche DOM Sinks in eurer Codebasis, entwerfen passende Trusted Types Policies und begleiten die schrittweise Migration von Report Only bis zum harten Enforcement Modus.

Sink Audit

Identifikation aller innerHTML, eval und Script Src Zuweisungen

Policy Design

Spezifische Policies pro Datenfluss statt pauschaler default Policy

Framework Integration

Angular, React und Legacy Bibliotheken Trusted Types kompatibel machen

Wer die Trusted Types API in einem bestehenden Magento oder Hyvä Frontend einführen möchte, sollte zunächst die Layout XML generierten Skripte und die Alpine.js Komponenten auf direkte innerHTML Zuweisungen prüfen, bevor die Content Security Policy Direktive aktiviert wird. Das verhindert, dass zentrale UI Komponenten nach der Aktivierung unerwartet leer bleiben.

10. Zusammenfassung

Die Trusted Types API schließt eine Lücke, die eine Content Security Policy allein nicht abdecken kann: unsichere Zuweisungen an DOM Sinks durch den eigenen, vertrauenswürdigen Anwendungscode. Über require-trusted-types-for 'script' aktiviert, akzeptiert der Browser an geschützten Sinks nur noch Werte, die zuvor durch eine registrierte Policy gelaufen sind. Named Policies für kritische Datenflüsse und eine default Policy als Migrationsnetz ergänzen sich, wobei die default Policy nie die einzige dauerhafte Lösung sein sollte.

Report Only Modus, Feature Detection für nicht unterstützte Browser und die Integration bestehender Sanitizer Bibliotheken wie DOMPurify machen die Einführung der Trusted Types API praktisch handhabbar, auch in großen, gewachsenen Codebasen. Wer DOM basiertes Cross Site Scripting nicht nur durch Konvention, sondern durch erzwungene Typprüfung im Browser ausschließen will, kommt an der Trusted Types API als zusätzlicher Sicherheitsschicht nicht vorbei.

Trusted Types API im Detail — Das Wichtigste auf einen Blick

Vier Bausteine, die zusammen die Trusted Types API im Alltag praktisch handhabbar machen.

Aktivierung

require-trusted-types-for 'script' in der Content Security Policy erzwingt Typprüfung an geschützten DOM Sinks.

Policies

createHTML, createScript und createScriptURL transformieren rohe Strings in vertrauenswürdige Typen.

default Policy

Sicherheitsnetz für Legacy Code, kein Ersatz für spezifische Policies pro Datenfluss.

Browser Support

Chrome und Edge nativ, Firefox und Safari eingeschränkt. Feature Detection ist Pflicht.

Zusammen ergeben diese vier Bausteine eine praxistaugliche Migrationsstrategie für gewachsene Frontend Codebasen.

11. FAQ: Trusted Types API im Detail

1Was ist die Trusted Types API?
Eine Browser API, die gefährliche DOM Sinks nur noch durch Policies erzeugte Typen akzeptieren lässt und DOM XSS strukturell verhindert.
2Wie aktiviere ich Trusted Types?
Über require-trusted-types-for 'script' in der Content Security Policy.
3Was macht eine default Policy?
Greift automatisch bei Strings ohne explizite Policy. Migrationsnetz, keine Dauerlösung.
4Welche DOM Sinks werden geschützt?
innerHTML, outerHTML, document.write, script src sowie eval und setTimeout mit String Argument.
5Unterstützen alle Browser Trusted Types?
Nein, Chrome und Edge nativ, Firefox und Safari eingeschränkt. Feature Detection ist Pflicht.
6Ersetzt Trusted Types eine Sanitizer Bibliothek?
Nein, die Bereinigungslogik liefert weiterhin eine Bibliothek wie DOMPurify innerhalb der Policy.
7Wie migriere ich eine große Codebasis?
Erst Report Only, dann default Policy, zuletzt spezifische Policies pro Datenfluss.
8Funktioniert Trusted Types mit Angular oder React?
Angular nativ, React seltener direkt, außer bei dangerouslySetInnerHTML.
9Was passiert ohne Feature Detection?
createPolicy wirft eine Exception, wenn window.trustedTypes fehlt. Ohne Prüfung stürzt die Initialisierung ab.
10Kann jeder Code beliebige Policies registrieren?
Nur ohne Einschränkung durch die trusted-types Direktive. Eine explizite Liste verhindert unautorisierte Policy Registrierung.