Skip to content

Cross-Site Scripting durch Filter verhindern

Wir hatten ja schon festgestellt, dass die einfachste Lösung zum Verhindern von XSS, das Verbieten von HTML und damit JavaScript als Benutzereingabe, heutzutage sehr oft nicht mehr möglich ist.

Dass die Benutzer aber manuell HTML-Code eingeben kann man meist auch nicht erwarten, welcher normale Benutzer "spricht" schon HTML? Oder eine andere Auszeichnungssprache wie BBCode? Womit diese Lösung ebenfalls ausscheidet.

Unser Tool, unsere Daten, also alles ganz harmlos?

Wir leben in der Zeit des Web 2.0 (oder schon dessen Nachfolgers?), wer "User generated Content" erwartet, muss den User dafür schon geeignete Werkzeuge zur Verfügung stellen. Am besten einen WYSIWYG-Editor im Browser wie er zum Beispiel von TinyMCE bereit gestellt wird. Das löst dann auch das Problem des Cross-Site Scriptings, oder?

Denn wenn die Daten vom Client-Code der Webanwendung stammen, brauchen wir uns auf den Server um diese Eingabe ja gar nicht mehr zu kümmern. Der WYSIWYG-Editor im Browser lässt natürlich keine Angriffe durch, richtig?

Wie bereits erwähnt ist das natürlich nicht der Fall. Denn auch hier gilt der altbekannte Grundsatz der Websicherheit, "Traue nie dem Client".

Nur, weil eine Eingabe anscheinend vom eigenen Client-Code stammt, muss sie noch lange nicht harmlos sein. Ein Angreifer könnte den Client manipuliert haben, so dass er darüber trotz eigentlich vorhandener Schutzfunktionen Schadcode einschleusen kann. Oder er kann den vom Client-Code gesendeten Request in einem Proxy abfangen und nach seinen Wünschen manipulieren. Oder seine Daten ganz unabhängig vom Client mit einem Tool seiner Wahl an die Webanwendung schicken.

Also: Alles, was vom Client kommt, muss geprüft werden. Nur wenn es erwiesen harmlos ist, darf es weiter verwendet werden. Der Einfachheit halber verwendet man dafür meist eine Filterfunktion, die möglicherweise eingeschleusten Code aus der Eingabe löscht. Wenn kein Schadcode drin ist, richtet der Filter keinen Schade an, wenn doch, ist der Schadcode danach (hoffentlich) weg und die Eingabe harmlos.

Und bevor ich es vergesse: Was WYSIWYG-Editoren betrifft - Die können selbst zum Einfallstor für XSS-Angriffe werden, wie zum Beispiel eine Schwachstelle in TinyMCE beweist (die allerdings nur im IE 8 und davor ausgenutzt werden konnte).

Tags ausfiltern, Stufe 1

Am einfachsten ist das Ausfiltern von HTML-Tags mit Hilfe der entsprechenden Funktionen der Programmiersprachen, im Fall von PHP also mit den Funktionen strip_tags, htmlentities und htmlspecialchars.

strip_tags versucht(!) ("This function tries to return a string with all NULL bytes, HTML and PHP tags stripped ...") aus dem Eingabestring alle NULL-Bytes, HTML- und PHP-Tags zu löschen, wobei optional eine Liste zulässiger HTML-Tags angegeben werden kann. HTML-Kommentare und PHP-Tags werden immer gelöscht.

Da die Funktion das HTML nicht validiert, ist nicht garantiert, dass wirklich alle Tags, vor allem alle falsch formatierten Tags, entfernt werden. Außerdem bleiben in erlaubten Tags alle Attribute enthalten, auch solche, über die sich XSS einschleusen lässt. Und auch die Funktionen htmlentities (wandelt alle Zeichen in HTML-Entities um, bei denen das möglich ist) und htmlspecialchars (wandelt nur die kritischen Zeichen <, >, &, " und ' in HTML-Entities um) kann nicht alle möglichen XSS-Angriffen verhindern.

Je nachdem, in welchem Kontext der eingeschleuste Code landet, ist ein Angriff auch ohne die ausgefilterten Zeichen und/oder Tags möglich. Mit den Funktionen strip_tags und Co. lässt sich XSS nur im Kontext von HTML und JavaScript-Code verhindern, im Kontext von Attributen (s.o.), Styles und URLs eingeschleuster Code wird damit nicht zuverlässig ausgefiltert, so dass der Filter umgangen werden kann.

Tags ausfiltern, Stufe 2

Wenn die Sprach-eigenen Funktionen zum Ausfiltern von XSS nicht immer zuverlässig sind muss man sich eben selbst was ausdenken - oder vorhandene Filterfunktionen Dritter verwenden. Das erste ist gar nicht so einfach, weshalb das zweite oft auch nicht besonders sicher ist.

Etwas besser sieht es bei den auf das Filtern von Eingaben spezialisierten Frameworks wie zum Beispiel HTML Purifier und htmLawed aus, und auch allgemeine Frameworks für Webanwendungen wie zum Beispiel CodeIgniter stellen entsprechende Funktionen bereit. Wobei zumindest der Filter von CodeIgniter nur im HTML-Kontext verwendet werden sollte.

Generell gilt bei sicherheitsrelevanten Komponenten noch mehr als sonst, dass immer die aktuellste Version der Software verwendet werden muss. Zum einen, damit sie keine bekannten Schwachstellen enthält, zum anderen, damit sie an alle aktuellen Entwicklungen angepasst ist. Gibt es längere Zeit kein Update, sollte man sich davon überzeugen, dass die Schutzfunktionen wirklich noch so funktionieren, wie man das erwartet.

Alles lebt!

Die Entwicklung eines wirklich sicheren Filters ist aber auch gar nicht so einfach. Immer, wenn man denkt, man hat alle Möglichkeiten für einen Angriff erfasst, kommt jemand und entwickelt eine neue Möglichkeit, die vom Filter nicht erfasst wird.

Sofern man nicht komplett auf HTML in der Eingabe verzichten will, muss man mit den Risiko leben, dass der Filter irgendwann ausgetrickst wird. HTML5 ist ein "lebender Standard", und auch die Browser-Entwickler probieren immer mal wieder was Neues aus. Auf der "Gegenseite" denken sich die Sicherheitsforscher und zumindest teilweise die Cyberkriminellen immer wieder neue Angriffsmöglichkeiten aus. Da bleibt es nicht aus, dass die XSS-Filter mal der Entwicklung hinterher hinken.

Um so wichtiger ist es daher, dass sie immer wieder an die neuen Angriffe angepasst werden. Ein Filter, der jetzt in diesem Moment alle Angriffe ausfiltert, wird spätestens in einem Jahr irgendwo und irgendwie ausgetrickst werden können. Der dann mögliche Angriff betrifft dann sehr wahrscheinlich nur einen mehr oder weniger großen (oder kleinen) Teil der Benutzer, aber das reicht schon, um Schaden anzurichten.

Darum noch einmal der Hinweis: Achten Sie darauf, immer die aktuellste Versionen der gewählten Frameworks zu verwenden bzw. passen Sie ihren eigenen XSS-Filter regelmäßig an die aktuellen Entwicklungen an. Vermutlich also mindestens jedes Frühjahr und jeden Herbst nach den bekannten Sicherheitskonferenzen.

Und damit ist das Thema Cross-Site Scripting auch erst mal abgeschlossen. Sie haben sicher bemerkt, dass die Suche nach Persistenten und DOM-basierten XSS-Schwachstellen noch nicht behandelt wurde, aber die habe ich mit Absicht vorerst ausgelassen. Ich werde sie sicher irgendwann später nachreichen, aber ab der nächsten Woche sind erst mal wieder aktuellere Themen dran.

Carsten Eilers

Trackbacks

Keine Trackbacks