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, mit dem beliebiger JavaScript-Code ausgeführt werden kann.
DOM XSS ist eine der häufigsten Sicherheitslücken im Web und es kommt häufig vor, dass Entwicklungsteams sie versehentlich in ihre Apps einführen. Vertrauenswürdige Typen geben Ihnen die Möglichkeit, Anwendungen zu schreiben, Sicherheitsüberprüfungen durchzuführen und sie frei von DOM XSS -Sicherheitslücken zu halten. Dazu werden gefährliche Web-API-Funktionen standardmäßig sicher gemacht. Vertrauenswürdige Typen 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, aus dem die Website besteht, auf unsichere Weise erstellt. Andere haben eine Ursache auf dem Client, wo der JavaScript-Code gefährliche Funktionen mit vom Nutzer gesteuerten Inhalten aufruft.
Um serverseitiges XSS zu verhindern, sollten Sie HTML nicht durch Verketten von Strings generieren. Verwenden Sie stattdessen sichere kontextbezogene Templating-Bibliotheken mit automatischer Escaping-Funktion sowie eine nonce-basierte Content Security Policy um weitere Fehler zu vermeiden.
Browser können jetzt auch dazu beitragen, clientseitiges DOM-basiertes XSS zu verhindern, indem sie vertrauenswürdige Typen verwenden.
Einführung in die API
Vertrauenswürdige Typen sperren die folgenden riskanten Senkenfunktionen. Einige davon kennen Sie möglicherweise bereits, da Browseranbieter und Web-Frameworks aus Sicherheitsgründen bereits davon abraten, diese Funktionen zu verwenden.
- Skriptmanipulation:
<script src>und Festlegen von Textinhalten von<script>-Elementen. - HTML aus einem String generieren:
- Plugin-Inhalte ausführen:
- JavaScript-Code zur Laufzeit kompilieren:
evalsetTimeoutsetIntervalnew Function()
Bei vertrauenswürdigen Typen müssen Sie die Daten verarbeiten, bevor Sie sie an diese Senkenfunktionen übergeben. Die Verwendung eines Strings allein schlägt 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
sensible Senken.
Vertrauenswürdige Typen reduzieren die DOM XSS Angriffsfläche Ihrer Anwendung erheblich. Sie vereinfachen Sicherheitsüberprüfungen und ermöglichen es Ihnen, die typbasierten Sicherheitsprüfungen zu erzwingen, die beim Kompilieren, Linten oder Bündeln Ihres Codes zur Laufzeit im Browser durchgeführt werden.
Vertrauenswürdige Typen verwenden
Berichte zu Verstößen gegen die Content Security Policy vorbereiten
Sie können einen Berichtssammler wie den Open-Source-Berichts-API-Prozessor oder go-csp-collector bereitstellen oder eine der kommerziellen Alternativen verwenden. 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 den folgenden HTTP-Antwortheader zu Dokumenten hinzu, die Sie zu vertrauenswürdigen Typen migrieren möchten:
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Jetzt werden alle Verstöße an //my-csp-endpoint.example gemeldet, die Website funktioniert aber weiterhin. Im nächsten Abschnitt wird erläutert, wie //my-csp-endpoint.example funktioniert.
Verstöße gegen vertrauenswürdige Typen erkennen
Wenn vertrauenswürdige Typen 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"
}
}
Daraus geht hervor, dass in https://my.url.example/script.js in Zeile 39 innerHTML mit dem String aufgerufen wurde, der mit <img src=x beginnt. Mit diesen Informationen können Sie eingrenzen, welche Teile des Codes möglicherweise 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 fehlerhaften Code entfernen, eine Bibliothek verwenden, eine Richtlinie für vertrauenswürdige Typen erstellen oder als letzten Ausweg eine Standardrichtlinie erstellen.
Fehlerhaften Code neu schreiben
Möglicherweise wird der nicht konforme Code nicht mehr benötigt oder kann ohne die Funktionen neu geschrieben werden, die die Verstöße verursachen:
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 vertrauenswürdige Typen, die Sie an die Senkenfunktionen übergeben können. Mit DOMPurify können Sie beispielsweise ein HTML-Snippet bereinigen und XSS-Payloads entfernen.
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});
DOMPurify unterstützt vertrauenswürdige Typen
und gibt bereinigtes HTML zurück, das in ein TrustedHTML Objekt eingebunden ist, sodass 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 Sie den Wert bereinigen und einen vertrauenswürdigen Typ erstellen können. In diesen Fällen können Sie selbst ein Objekt für vertrauenswürdige Typen 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, '<')
});
}
Dieser Code erstellt eine Richtlinie namens myEscapePolicy, mit der TrustedHTML-Objekte mithilfe der Funktion createHTML() erstellt werden können. Die definierten Regeln führen ein HTML-Escaping für <-Zeichen durch, um die Erstellung neuer HTML-Elemente zu verhindern.
Verwenden Sie die Richtlinie so:
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 fehlerhaften Code nicht ändern, z. B. wenn Sie eine Drittanbieterbibliothek aus 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 verwendet, wo ein String in einer Senke verwendet wird, die nur vertrauenswürdige Typen akzeptiert.
Content Security Policy erzwingen
Wenn Ihre Anwendung keine Verstöße mehr verursacht, können Sie vertrauenswürdige Typen erzwingen:
Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Unabhängig davon, wie komplex Ihre Webanwendung ist, kann jetzt nur noch der Code in einer Ihrer Richtlinien eine DOM XSS-Sicherheitslücke verursachen. Sie können dies noch weiter einschränken, indem Sie die Erstellung von Richtlinien begrenzen.