- Um XSS-Angriffe, eine der wichtigsten Schwachstellen des Webs, zu verhindern, unterstützt Firefox als erster Browser die standardisierte Sanitizer API
- Wird statt des bisherigen innerHTML die Methode setHTML() verwendet, wird nicht vertrauenswürdiges HTML vor dem Einfügen in das DOM automatisch bereinigt (sanitized) und bösartiges Skript entfernt
- Wenn die Standardeinstellungen zu streng oder zu locker sind, können Entwickler über eine benutzerdefinierte Konfiguration steuern, welche Elemente und Attribute erlaubt sind
- In Kombination mit Trusted Types hebt diese Funktion in Firefox das allgemeine Sicherheitsniveau im Web an und ermöglicht es Entwicklern, XSS auch ohne separates Sicherheitsteam zu verhindern
XSS-Schwachstellen und Firefox’ Gegenmaßnahmen
- Cross-Site Scripting (XSS) entsteht, wenn Angreifer über von Nutzern eingegebene Inhalte beliebiges HTML oder JavaScript einschleusen können
- Angreifer können dies nutzen, um Nutzerinteraktionen zu überwachen oder Daten zu stehlen
- XSS wird seit fast 10 Jahren als eine der Top-3-Webschwachstellen (CWE-79) eingestuft
- Firefox stärkt die XSS-Abwehr seit 2009, indem es den Standard Content-Security-Policy (CSP) vorantreibt
- CSP beschränkt, welche Ressourcen eine Website laden und ausführen darf
- Wegen nötiger Änderungen an bestehenden Website-Strukturen und fortlaufender Sicherheitsprüfungen gab es jedoch Grenzen für eine breite Einführung
Die Rolle von Sanitizer API und setHTML()
- Die Sanitizer API bietet einen standardisierten Weg, bösartiges HTML in eine harmlose Form umzuwandeln
- Im Codebeispiel wird das Element
<img src="x" onclick="alert('XSS')"> entfernt, und nur <h1>Hello my name is</h1> bleibt übrig
- Die Methode setHTML() führt beim Einfügen von HTML automatisch eine Bereinigung durch und gewährleistet damit ein standardmäßig sicheres Verhalten
- Schon der Austausch einer
innerHTML-Zuweisung durch setHTML() ermöglicht eine starke XSS-Abwehr
- Falls die Standardeinstellungen zu strikt oder zu locker sind, können Entwickler über eine Custom-Konfiguration festlegen, welche HTML-Elemente und Attribute erlaubt sind
- Für Experimente kann das Tool Sanitizer API playground genutzt werden
Kombination mit Trusted Types
- Die Trusted Types API bietet eine zusätzliche Sicherheitsschicht, indem sie das Parsen und Einfügen von HTML zentral steuert
- Bei der Verwendung von
setHTML() lassen sich Trusted-Types-Richtlinien einfach anwenden
- Eine strenge Richtlinie erlaubt nur
setHTML() und blockiert andere riskante Einfügemethoden, was zur Vermeidung künftiger XSS-Regressionen beiträgt
Sicherheitsverbesserungen in Firefox 148
- Firefox 148 unterstützt sowohl die Sanitizer API als auch Trusted Types und verbessert das grundlegende Sicherheitsniveau deutlich
- Entwickler können XSS schon mit einfachen Codeänderungen verhindern, ganz ohne komplexe Sicherheitsrichtlinien oder ein separates Sicherheitsteam
- Von der Einführung dieses Standards wird erwartet, dass sie die Verbreitung eines sichereren Webs in allen Browsern fördert
Zusammenfassung
- Firefox 148 unterstützt Webentwickler mit der setHTML()-Methode und der Sanitizer API dabei, XSS-Angriffe einfach zu blockieren
- Die Funktion ergänzt die Grenzen von CSP und ist ein Schritt hin zu einem standardmäßig sicheren Verfahren für das Einfügen von HTML als Webstandard
- In Kombination mit Trusted Types werden langfristige Sicherheit und die Vermeidung von XSS-Regressionen möglich
- Damit treibt Firefox den Wandel hin zu einem Web, in dem Sicherheit der Standard ist, voran
2 Kommentare
Oh, so etwas braucht man auf jeden Fall. Wenn das in allen Browsern unterstützt wird, wäre das wirklich großartig.
Hacker-News-Kommentare
Solche Funktionen wirken immer etwas beunruhigend
Es gibt dann eine Mischung aus Methoden, die auch mit beliebigen Benutzereingaben sicher umgehen, und solchen, die das nicht tun, aber allein am Namen ist das schwer zu erkennen
Idealerweise sollte schon von Anfang an im Namen klar erkennbar sein, welche Funktionen gefährlich sind
Außerdem ist das Konzept, HTML zu „sanitizen“, an sich vage, und es ist schwer zu beurteilen, ob es tatsächlich sicher ist
Elemente oder Attribute, mit denen sich Skripte ausführen lassen, werden entfernt, und diese Logik läuft innerhalb der Browser-Engine, wodurch sie präziser arbeitet als stringbasierte Sanitizer
Details dazu stehen in der MDN-Dokumentation zu setHTML
elementNode.textContentist auch bei nicht vertrauenswürdigen Eingaben sicher,elementNode.innerHTMLhingegen nichtErsteres escaped alle Zeichen, Letzteres gar keine
Manche vertreten die Ansicht, dass „HTML-Sanitization“ grundsätzlich ein unlösbares Problem ist
Siehe dazu diesen Kommentar
Eine solche API hätte die Vorschlagsphase gar nicht erst passieren dürfen
innerHTMLundsetHTMLparallel zu verwenden, hätte maninnerHTMLkomplett entfernen und für das alte VerhaltensetHTMLUnsafeanbieten solleninnerHTMLdeaktivieren könntenAllerdings könnte dann die Website in alten Browsern nicht mehr funktionieren
Content-Security-Policy: require-trusted-types-for 'script'ausgeliefert wird, lässt sich verhindern, dass an Methoden ohne Sanitizer gewöhnliche Strings übergeben werdenWenn man wie im Beispiel Tags wie
<h1>oder<br>in einen Benutzernamen einfügen kann, ist trotz blockierter Skriptausführung weiterhin beliebige Markup-Injektion möglichMit einem
<style>-Tag ließe sich auch CSS verändern und etwa das Design einer PayPal-Profilseite umgestaltenDa fragt man sich, wer so etwas wollen würde
Man kann eine zusätzliche Schutzschicht einbauen, indem man das aus Markdown erzeugte HTML nochmals durch einen Sanitizer einschränkt und nur bestimmte Tags zulässt
innerHTMLbesserinnerTextodertextContentverwenden sollensetHTMList als Ersatz fürinnerHTMLgedachtsetHTML()zu streng oder zu locker sind, kann der Entwickler eine benutzerdefinierte Konfiguration bereitstellen, in der erlaubte HTML-Elemente und Attribute direkt festgelegt werdenSiehe dazu diesen Thread
Letztlich muss man Benutzernamen also auch im Backend weiterhin auf die übliche Weise sanitizen und bei der Ausgabe HTML-Escaping anwenden
Laut RFC 2119 ist das eine Anforderung auf „SHOULD“-Niveau
Ich begrüße die Einführung dieser Funktion, aber es dürfte noch dauern, bis die Browser-Unterstützung ausreichend verbreitet ist
Den aktuellen Stand kann man bei Can I use prüfen
In der Zwischenzeit kann man auf ein Polyfill ausweichen
Der Titel war etwas reißerisch
Eigentlich ließe sich Sanitization doch auch mit einer Funktion umsetzen, die Eingaben prüft, bevor sie an
innerHTMLübergeben werdenSolche Versuche fühlen sich allerdings am Ende wie eine Neuerfindung des Rads an
Außerdem lässt sich hacks.mozilla.org in älteren Firefox-Versionen gar nicht öffnen, und in Pale Moon oder SeaMonkey wird MDN fehlerhaft dargestellt
Es wirkt fast so, als wolle ein „Browser-Kartell“ das Web kaputtmachen
Dabei wird noch nicht einmal das Problem unterschiedlicher Parserinterpretationen (parser differential) berücksichtigt
Die Sanitizer API kann bei falscher Verwendung zu einem Footgun werden
Besonders im „remove“-Modus ist Vorsicht geboten
Meiner Meinung nach wäre es besser, nur
setTextzu verwenden und Nutzern überhaupt kein HTML zu erlaubensetHTMLverwendet wird, tritt kein XSS aufWenn man sieht, wie häufig
innerHTMLverwendet wird, ist ein vollständiger Verzicht schwer vorstellbarBeeindruckend ist, dass inzwischen alle Aspekte des Netzwerkzugriffs sauber kontrolliert werden und sich die Sicherheitskette damit von Vertrauen in den Code zu Vertrauen in die Host-Konfiguration verschoben hat
Auch die Standardwerte sind sicher gesetzt
Was ich wirklich möchte, ist ein
<sandbox>-Element, mit dem sich gefährlicher Code sicher ausführen lässtNicht riskanten Code umzuschreiben, sondern ihn in einer isolierten Umgebung laufen zu lassen
iframes haben die Einschränkung, nicht zusammen mit dem DOM zu fließen, und in einer Zeit von AI und zunehmend dynamischen Inhalten braucht es komponierbare Kapselung
Den Namen
setHTMLUnsafefinde ich wirklich gutSicherheitsfunktionen scheitern, wenn Entwickler sich bewusst dafür entscheiden müssen
Effektiver ist es, „den gefährlichen Pfad auch gefährlich wirken zu lassen“
Der Name
set_html()ist viel intuitiver alsinner_htmlDie APIs in JavaScript sind wirklich ein ziemliches Durcheinander und müssten irgendwann aufgeräumt werden
In dieser Diskussion geht es zwar um Sicherheit, aber auch das Design neuer APIs sollte sauber sein
DOM-APIs vermitteln seit jeher, auch heute noch, den Eindruck, als seien sie von Leuten entworfen worden, die noch nie APIs gebaut haben
Entwickler in den 90ern:
Entwickler in den 2020ern:
Wir haben aus den 90ern nichts gelernt