DOM-basiertes Cross-Site-Scripting (DOM XSS) tritt auf, wenn Daten aus einer vom Nutzer gesteuerten Quelle (z. B. ein Nutzername oder eine Weiterleitungs-URL aus dem URL-Fragment) eine Senke erreichen. Eine Senke ist eine Funktion wie eval()
oder ein Property-Setter wie .innerHTML
, der beliebigen JavaScript-Code ausführen kann.
DOM XSS ist eine der häufigsten Sicherheitslücken im Web und Entwicklerteams führen sie oft versehentlich in ihre Apps ein. Trusted Types bieten Ihnen die Tools, um Anwendungen zu schreiben, Sicherheitsüberprüfungen durchzuführen und sie frei von DOM-XSS-Schwachstellen zu halten, indem gefährliche Web-API-Funktionen standardmäßig sicher gemacht werden. Trusted Types sind als Polyfill für Browser verfügbar, die sie noch nicht unterstützen.
Hintergrund
DOM-XSS ist seit vielen Jahren eine der häufigsten und gefährlichsten Sicherheitslücken im Web.
Es gibt zwei Arten von Cross-Site-Scripting. Einige XSS-Sicherheitslücken werden durch serverseitigen Code verursacht, der den HTML-Code der Website auf unsichere Weise erstellt. Andere haben eine Ursache auf dem Client, wo der JavaScript-Code gefährliche Funktionen mit nutzergesteuerten Inhalten aufruft.
Um serverseitiges XSS zu verhindern, sollten Sie HTML nicht durch Verketten von Strings generieren. Verwenden Sie stattdessen sichere Templating-Bibliotheken mit kontextbezogenem automatischen Escaping sowie eine Nonce-basierte Content Security Policy, um zusätzliche Fehler zu vermeiden.
Browser können jetzt auch dazu beitragen, clientseitige DOM-basierte XSS-Angriffe mithilfe von vertrauenswürdigen Typen zu verhindern.
Einführung in die API
Trusted Types funktionieren, indem die folgenden riskanten Senkenfunktionen gesperrt werden. Einige davon sind Ihnen vielleicht schon bekannt, da Browseranbieter und Web-Frameworks Sie aus Sicherheitsgründen bereits davon abhalten, diese Funktionen zu verwenden.
- Skriptbearbeitung:
<script src>
und Festlegen des Textinhalts von<script>
Elementen. - HTML aus einem String generieren:
- Plug-in-Inhalte ausführen:
- Kompilierung von JavaScript-Code zur Laufzeit:
eval
setTimeout
setInterval
new Function()
Bei Trusted Types müssen Sie die Daten verarbeiten, bevor Sie sie an diese Senkenfunktionen übergeben. Wenn Sie nur einen String verwenden, schlägt der Vorgang fehl, da der Browser nicht weiß, ob die Daten vertrauenswürdig sind:
anElement.innerHTML = location.href;
Um anzugeben, dass die Daten sicher verarbeitet wurden, erstellen Sie ein spezielles Objekt, einen vertrauenswürdigen Typ.
anElement.innerHTML = aTrustedHTML;
TrustedHTML
-Objekt für Senken, die HTML-Snippets erwarten. Es gibt auch TrustedScript
- und TrustedScriptURL
-Objekte für andere vertrauliche Senken.
Vertrauenswürdige Typen reduzieren die Angriffsfläche für DOM-XSS-Angriffe in Ihrer Anwendung erheblich. Das vereinfacht Sicherheitsüberprüfungen und ermöglicht es Ihnen, die typbasierten Sicherheitsprüfungen, die beim Kompilieren, Linting oder Bündeln Ihres Codes zur Laufzeit im Browser durchgeführt werden, zu erzwingen.
Trusted Types verwenden
Berichte zu CSP-Verstößen vorbereiten
Sie können einen Berichtssammler wie reporting-api-processor oder go-csp-collector (beides Open-Source-Projekte) oder eines der kommerziellen Äquivalente bereitstellen. Sie können auch benutzerdefiniertes Logging hinzufügen und Verstöße im Browser mit einem ReportingObserver debuggen:
const observer = new ReportingObserver((reports, observer) => {
for (const report of reports) {
if (report.type !== 'csp-violation' ||
report.body.effectiveDirective !== 'require-trusted-types-for') {
continue;
}
const violation = report.body;
console.log('Trusted Types Violation:', violation);
// ... (rest of your logging and reporting logic)
}
}, { buffered: true });
observer.observe();
oder indem Sie einen Event-Listener hinzufügen:
document.addEventListener('securitypolicyviolation',
console.error.bind(console));
CSP-Header nur für Berichte hinzufügen
Fügen Sie Dokumenten, die Sie zu Trusted Types migrieren möchten, den folgenden HTTP-Antwortheader hinzu:
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Alle Verstöße werden jetzt an //my-csp-endpoint.example
gemeldet, die Website funktioniert aber weiterhin. Im nächsten Abschnitt wird die Funktionsweise von //my-csp-endpoint.example
erläutert.
Verstöße gegen vertrauenswürdige Typen erkennen
Wenn Trusted Types ab sofort einen Verstoß erkennen, sendet der Browser einen Bericht an eine konfigurierte report-uri
. Wenn Ihre Anwendung beispielsweise einen String an innerHTML
übergibt, sendet der Browser den folgenden Bericht:
{
"csp-report": {
"document-uri": "https://my.url.example",
"violated-directive": "require-trusted-types-for",
"disposition": "report",
"blocked-uri": "trusted-types-sink",
"line-number": 39,
"column-number": 12,
"source-file": "https://my.url.example/script.js",
"status-code": 0,
"script-sample": "Element innerHTML <img src=x"
}
}
Das bedeutet, dass in https://my.url.example/script.js
in Zeile 39 innerHTML
mit dem String aufgerufen wurde, der mit <img src=x
beginnt. Diese Informationen sollten Ihnen helfen, einzugrenzen, welche Teile des Codes DOM XSS verursachen und geändert werden müssen.
Verstöße beheben
Es gibt mehrere Möglichkeiten, einen Verstoß gegen vertrauenswürdige Typen zu beheben. Sie können den betreffenden Code entfernen, eine Bibliothek verwenden, eine Trusted Types-Richtlinie erstellen oder als letzten Ausweg eine Standardrichtlinie erstellen.
Anstößigen Code umschreiben
Möglicherweise wird der nicht konforme Code nicht mehr benötigt oder kann ohne die Funktionen, die die Verstöße verursachen, neu geschrieben werden:
el.textContent = ''; const img = document.createElement('img'); img.src = 'xyz.jpg'; el.appendChild(img);
el.innerHTML = '<img src=xyz.jpg>';
Bibliothek verwenden
Einige Bibliotheken generieren bereits Trusted Types, die Sie an die Senkenfunktionen übergeben können. Sie können beispielsweise DOMPurify verwenden, um ein HTML-Snippet zu bereinigen und XSS-Payloads zu entfernen.
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});
DOMPurify unterstützt Trusted Types und gibt bereinigtes HTML zurück, das in ein TrustedHTML
-Objekt eingeschlossen ist, damit der Browser keinen Verstoß generiert.
Richtlinie für vertrauenswürdige Typen erstellen
Manchmal können Sie den Code, der den Verstoß verursacht, nicht entfernen und es gibt keine Bibliothek, mit der der Wert bereinigt und ein Trusted Type für Sie erstellt werden kann. In diesen Fällen können Sie selbst ein Trusted Type-Objekt erstellen.
Erstellen Sie zuerst eine Richtlinie. Richtlinien sind Factories für vertrauenswürdige Typen, die bestimmte Sicherheitsregeln für ihre Eingabe erzwingen:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
const escapeHTMLPolicy = trustedTypes.createPolicy('myEscapePolicy', {
createHTML: string => string.replace(/\</g, '<')
});
}
Mit diesem Code wird eine Richtlinie mit dem Namen myEscapePolicy
erstellt, mit der mithilfe der Funktion createHTML()
TrustedHTML
-Objekte erstellt werden können. Die definierten Regeln maskieren <
-Zeichen in HTML, um die Erstellung neuer HTML-Elemente zu verhindern.
So verwenden Sie die Richtlinie:
const escaped = escapeHTMLPolicy.createHTML('<img src=x onerror=alert(1)>');
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped; // '<img src=x onerror=alert(1)>'
Standardrichtlinie verwenden
Manchmal können Sie den betreffenden Code nicht ändern, z. B. wenn Sie eine Drittanbieterbibliothek von einem CDN laden. Verwenden Sie in diesem Fall eine Standardrichtlinie:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
trustedTypes.createPolicy('default', {
createHTML: (string, sink) => DOMPurify.sanitize(string, {RETURN_TRUSTED_TYPE: true})
});
}
Die Richtlinie mit dem Namen default
wird überall dort verwendet, wo eine Zeichenfolge in einer Senke verwendet wird, die nur Trusted Type akzeptiert.
Auf Erzwingung der Content Security Policy umstellen
Wenn Ihre Anwendung keine Verstöße mehr verursacht, können Sie die Durchsetzung von Trusted Types starten:
Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Unabhängig davon, wie komplex Ihre Webanwendung ist, kann eine DOM-XSS-Schwachstelle nur durch den Code in einer Ihrer Richtlinien entstehen. Sie können dies noch weiter einschränken, indem Sie die Erstellung von Richtlinien einschränken.