DOM-basierte Cross-Site-Scripting-Sicherheitslücken mit vertrauenswürdigen Typen verhindern

Verkleinern Sie die DOM-XSS-Angriffsfläche Ihrer Anwendung.

Krzysztof Kotowicz
Krzysztof Kotowicz

Warum ist das wichtig?

Das DOM-basierte Cross-Site-Scripting (DOM XSS) ist eine der häufigsten Sicherheitslücken im Web und lässt sich leicht in Ihre Anwendung einbinden. Mit vertrauenswürdigen Typen erhalten Sie die Tools zum Schreiben, für Sicherheitsüberprüfungen und zur Wartung von Anwendungen, die frei von DOM XSS-Sicherheitslücken sind, da die gefährlichen Web-API-Funktionen standardmäßig sicher sind. Vertrauenswürdige Typen werden in Chrome 83 unterstützt. Für andere Browser ist polyfill verfügbar. Unter Browserkompatibilität finden Sie aktuelle Informationen zur browserübergreifenden Unterstützung.

Hintergrund

Seit vielen Jahren ist DOM XSS eine der häufigsten – und gefährlichsten – Sicherheitslücken im Web.

Es gibt zwei verschiedene Gruppen von Cross-Site-Scripting. Einige XSS-Sicherheitslücken werden durch den serverseitigen Code verursacht, der den HTML-Code, der die Website bildet, unsicher erstellt. Andere wiederum haben eine Grundursache auf dem Client, bei der der JavaScript-Code gefährliche Funktionen mit nutzergesteuerten Inhalten aufruft.

Wenn Sie serverseitiges XSS verhindern möchten, generieren Sie kein HTML durch Verkettung von Strings. Verwenden Sie stattdessen sichere Vorlagenbibliotheken für kontextbezogene automatische Escapesequenzen. Nutzen Sie eine Nonce-basierte Content Security Policy, um Programmfehler zu vermeiden, die unvermeidlich auftreten.

Jetzt kann mit einem Browser auch clientseitige (auch als DOM-basierte) XSSes mit vertrauenswürdigen Typen verhindert werden.

API-Einführung

Vertrauenswürdige Typen funktionieren, indem die folgenden riskanten Senkenfunktionen gesperrt werden. Einige davon kennen Sie vielleicht schon, da Sie aus Sicherheitsgründen von Browseranbietern und Web-Frameworks abgehalten werden.

Bei vertrauenswürdigen Typen müssen Sie die Daten verarbeiten, bevor Sie sie an die oben genannten Senkenfunktionen übergeben. Die Verwendung eines Strings allein schlägt fehl, da der Browser nicht weiß, ob die Daten vertrauenswürdig sind:

Don'ts
anElement.innerHTML  = location.href;
Wenn vertrauenswürdige Typen aktiviert sind, gibt der Browser einen TypeError aus und verhindert die Verwendung einer DOM-XSS-Senke mit einem String.

Um anzugeben, dass die Daten sicher verarbeitet wurden, erstellen Sie ein spezielles Objekt – einen vertrauenswürdigen Typ.

Das sollten Sie tun:
anElement.innerHTML = aTrustedHTML;
Wenn vertrauenswürdige Typen aktiviert sind, akzeptiert der Browser ein 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. Es vereinfacht Sicherheitsprüfungen und ermöglicht Ihnen, die typbasierten Sicherheitsprüfungen zu erzwingen, die beim Kompilieren, Linting oder Bündeln Ihres Codes zur Laufzeit im Browser durchgeführt werden.

Vertrauenswürdige Typen verwenden

Auf Meldungen zu Verstößen gegen die Content Security Policy vorbereiten

Sie können ein Report Collector wie den Open-Source-Code go-csp-collector bereitstellen oder ein kommerzielles Äquivalent verwenden. Sie können die Verstöße auch im Browser beheben: js document.addEventListener('securitypolicyviolation', console.error.bind(console));

CSP-Header nur für Berichte hinzufügen

Fügen Sie Dokumenten, die zu vertrauenswürdigen Typen migriert werden sollen, den folgenden HTTP-Antwortheader hinzu. text 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, aber die Website funktioniert weiterhin. Im nächsten Abschnitt wird die Funktionsweise von //my-csp-endpoint.example erläutert.

Verstöße gegen vertrauenswürdige Typen identifizieren

Ab jetzt wird jedes Mal, wenn vertrauenswürdige Typen einen Verstoß erkennen, eine Meldung an eine konfigurierte report-uri gesendet. 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"
}
}

Dies besagt, dass in https://my.url.example/script.js in Zeile 39 innerHTML mit der Zeichenfolge aufgerufen wurde, die mit <img src=x beginnt. Mithilfe dieser Informationen können Sie eingrenzen, welche Codeteile möglicherweise DOM XSS einführen und geändert werden müssen.

Verstöße beheben

Es gibt mehrere Möglichkeiten, einen Verstoß gegen den vertrauenswürdigen Typ zu beheben. Sie können den anstößigen Code entfernen, eine Bibliothek verwenden, eine Richtlinie für vertrauenswürdigen Typ erstellen oder als letzte Option eine Standardrichtlinie erstellen.

Den betreffenden Code umschreiben

Vielleicht wird die nicht konforme Funktionalität nicht mehr benötigt oder kann auf moderne Weise ohne die fehleranfälligen Funktionen umgeschrieben werden?

Don'ts
el.innerHTML = '';
Das sollten Sie tun:
el.textContent = '';
const img = document.createElement('img');
img.src = 'xyz.jpg';
el.appendChild(img);

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-Nutzlasten zu entfernen.

import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});

DOMPurify unterstützt vertrauenswürdige Typen und gibt bereinigten HTML-Code zurück, der in ein TrustedHTML-Objekt eingebettet ist, sodass der Browser keinen Verstoß generiert.

Richtlinie für vertrauenswürdigen Typ erstellen

Manchmal ist es nicht möglich, die Funktion zu entfernen, und es gibt keine Bibliothek, um den Wert zu bereinigen und einen vertrauenswürdigen Typ für Sie zu erstellen. Erstellen Sie in diesen Fällen selbst ein vertrauenswürdiges Objekt.

Erstellen Sie dazu zuerst eine Richtlinie. Richtlinien sind Factorys für vertrauenswürdige Typen, die bestimmte Sicherheitsregeln für ihre Eingaben erzwingen:

if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
  const escapeHTMLPolicy = trustedTypes.createPolicy('myEscapePolicy', {
    createHTML: string => string.replace(/\</g, '&lt;')
  });
}

Mit diesem Code wird eine Richtlinie mit dem Namen myEscapePolicy erstellt, die über ihre Funktion createHTML() TrustedHTML-Objekte erstellen kann. Bei den definierten Regeln werden <-Zeichen in HTML maskiert, 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;  // '&lt;img src=x onerror=alert(1)>'

Standardrichtlinie verwenden

Manchmal lässt sich der betreffende Code nicht ändern. Das ist beispielsweise der Fall, 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 immer dann verwendet, wenn ein String in einer Senke verwendet wird, die nur vertrauenswürdigen Typ akzeptiert.

Zur Erzwingung der Content Security Policy wechseln

Wenn Ihre Anwendung keine Verstöße mehr verursacht, können Sie damit beginnen, vertrauenswürdige Typen zu erzwingen:

Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example

Fertig! 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 dies noch weiter sperren, indem Sie die Erstellung von Richtlinien einschränken.

Weitere Informationen