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) einen Senke erreichen. Dies ist eine Funktion wie eval()
oder ein Eigenschafts-Setter wie .innerHTML
, mit dem beliebiger JavaScript-Code ausgeführt werden kann.
DOM-XSS ist eine der häufigsten Sicherheitslücken in der Websicherheit. Entwicklerteams führen sie häufig versehentlich in ihren Apps ein. Mit Trusted Types haben Sie die Möglichkeit, Anwendungen zu schreiben, zu prüfen und frei von DOM-XSS-Sicherheitslücken zu halten, indem gefährliche Web-API-Funktionen standardmäßig sicher gemacht werden. Vertraute 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 websiteübergreifendem Scripting. Einige XSS-Sicherheitslücken werden durch serverseitigen Code verursacht, der den HTML-Code für die Website auf unsichere Weise erstellt. Andere haben ihre Ursache auf dem Client, wo der JavaScript-Code gefährliche Funktionen mit von Nutzern gesteuerten Inhalten aufruft.
Um serverseitiges XSS zu verhindern, sollten Sie HTML nicht durch Zusammenführen von Strings generieren. Verwenden Sie stattdessen sichere Vorlagenbibliotheken mit automatischem Kontext-Escaping und eine noncebasierte Content Security Policy, um Bugs zu vermeiden.
Mit Trusted Types können Browser jetzt auch clientseitige DOM-basierte XSS-Angriffe verhindern.
Einführung in die API
Bei vertrauenswürdigen Typen werden die folgenden unsicheren Sink-Funktionen gesperrt. Einige davon kennen Sie vielleicht bereits, da Browseranbieter und Web-Frameworks Sie aus Sicherheitsgründen von der Verwendung dieser Funktionen abraten.
- Script-Manipulation:
<script src>
und Textinhalte von Elementen vom Typ<script>
festlegen. - HTML aus einem String generieren:
- Plugin-Inhalte ausführen:
- Laufzeitkompilierung von JavaScript-Code:
eval
setTimeout
setInterval
new Function()
Bei vertrauenswürdigen Typen müssen Sie die Daten verarbeiten, bevor Sie sie an diese Senkenfunktionen übergeben. Die Verwendung eines Strings allein funktioniert nicht, 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;
Mit vertrauenswürdigen Typen lässt sich die Angriffsfläche für DOM-XSS-Angriffe Ihrer Anwendung erheblich reduzieren. Es vereinfacht die Sicherheitsüberprüfungen und ermöglicht es Ihnen, die typbasierten Sicherheitsprüfungen zu erzwingen, die beim Kompilieren, Linieren oder Bündeln Ihres Codes zur Laufzeit im Browser ausgeführt werden.
Vertraute Typen verwenden
Auf Berichte zu Verstößen gegen die Content Security Policy vorbereiten
Sie können einen Berichts-Collector wie den Open-Source-Dienst reporting-api-processor oder go-csp-collector bereitstellen oder eines der kommerziellen Äquivalente verwenden. Mit einem ReportingObserver können Sie auch benutzerdefinierte Protokolle und Fehlerbehebungen im Browser hinzufügen:
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 durch Hinzufügen eines Ereignis-Listeners:
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
Alle Verstöße werden jetzt 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 identifizieren
Ab sofort sendet der Browser jedes Mal, wenn Trusted Types einen Verstoß erkennt, 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 der Zeichenfolge aufgerufen wurde, die mit <img src=x
beginnt. Anhand dieser Informationen können Sie eingrenzen, welche Codeteile 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.
Den fehlerhaften Code umschreiben
Möglicherweise ist der nicht konforme Code nicht mehr erforderlich oder kann ohne die Funktionen umgeschrieben 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. Sie können beispielsweise DOMPurify verwenden, um ein HTML-Snippet zu bereinigen und XSS-Nutzlast zu entfernen.
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});
DOMPurify unterstützt vertrauenswürdige Typen und gibt gereinigte HTML-Inhalte in einem TrustedHTML
-Objekt zurück, 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 vertrauenswürdiger Typ für Sie erstellt werden kann. In diesen Fällen können Sie ein Objekt vom Typ „Vertrauenswürdiger Typ“ selbst erstellen.
Erstellen Sie zuerst eine Richtlinie. Richtlinien sind Fabriken für vertrauenswürdige Typen, die bestimmte Sicherheitsregeln auf ihre Eingaben anwenden:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
const escapeHTMLPolicy = trustedTypes.createPolicy('myEscapePolicy', {
createHTML: string => string.replace(/\</g, '<')
});
}
Mit diesem Code wird eine Richtlinie namens myEscapePolicy
erstellt, mit der über die Funktion createHTML()
TrustedHTML
-Objekte erstellt werden können. Die definierten Regeln führen zu einem HTML-Escape von <
-Zeichen, um das Erstellen 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 Bibliothek eines Drittanbieters 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 dort verwendet, wo ein String in einem Sink verwendet wird, der nur vertrauenswürdige Typen akzeptiert.
Zur Erzwingung der Content Security Policy wechseln
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 nur der Code in einer Ihrer Richtlinien eine DOM-XSS-Sicherheitslücke verursachen. Sie können diese Lücke noch weiter schließen, indem Sie die Richtlinienerstellung einschränken.