Eingehendes HTML in PHP sicher verarbeiten

Hyperactive
Kommentare

Schöne neue Welt des Web 2.0: Die hoch motivierten Besucher Ihrer Webseite schreiben fleißig Kommentare, bloggen wie die Weltmeister und füllen das Forum im regen Austausch mit Anderen mit nützlichen Informationen. Doch wie sieht es mit der Sicherheit aus?

HTML ist das grundlegende Element des Web, denn ohne die Hypertext-Markup-Language sind moderne Webseiten nicht möglich. Es gibt zwar diverse Ansätze, dem Autor eines Kommentars, Beitrags oder Blog-Eintrags das Lernen von HTML abzunehmen, aber sei es nun BBCode, Wiki-Text oder ein anderes Format – sie alle nötigen den Benutzer dazu, eine meist nur auf der gerade besuchten Website funktionierende proprietäre Auszeichnungssprache zu erlernen. Glücklicherweise trifft man in der Praxis zur Übermittlung des User-generated Content zunehmend reine WYSIWYG-Editoren an, die den Part der Umsetzung der Textauszeichnungsidee in ein beliebiges Markup übernehmen, ohne den Benutzer damit zu belasten.

Wer jedoch auf seiner Webseite einen derartigen Editor einsetzt, wird Server-seitig mit einer Vielzahl von Problemen konfrontiert: Neben dem Thema Sicherheit stellt sich auch die Frage nach der Fehlertoleranz. Grundsätzlich ist zwar davon auszugehen, dass ein WYSIWYG-Editor, wenn vielleicht auch keinen schönen, so doch aber zumindest syntaktisch gültigen Quelltext erzeugen wird. Dass ein Anwender hier trotzdem eigene Code-Fragmente einschleusen kann, muss bei der Weiterverarbeitung der Eingaben durch das Backend berücksichtigt werden. Denn neben ungewollt eingefügten syntaktischen Fehlern kann so auch bewusst Schadcode für XSS (siehe Kasten „XSS-Spielarten“) und Co. übermittelt werden. Viele Anleitungen zum Umgang mit Benutzereingaben empfehlen, einfach grundsätzlich kein HTML zuzulassen und verweisen daher auf die Methode strip_tags(). So sinnvoll dieses Vorgehen bei allen Eingaben, die keines innertextuellen Markups bedürfen, auch sein mag, bei der Verarbeitung von Daten der WYSIWYG-Editoren wäre dies kontraproduktiv. Die einzige Möglichkeit ist daher ein händischer Check der übermittelten Struktur.

Parsen per Whitelist

Bevor Sie sich der eigentlichen Analyse eines Dokumentes zuwenden, müssen Sie einige grundsätzliche Dinge klären: Zunächst stellt sich die Frage, ob Sie mit einer Blacklist verbotene Elemente aus der Datei entfernen oder eher das Dokument anhand einer Whitelist durchgehen und alles, was nicht explizit erlaubt ist, löschen. Die Erfahrung lehrt, dass Blacklistings per se unsicher sind, eine paranoide Whitelist aber auch erwünschte Konstrukte als bösartig einstufen und verwerfen kann. Als sicherheitsbewusster Entwickler sollten Sie dennoch klar die Whitelist favorisieren. Als Nächstes stehen die verschiedenen Ansätze zum Parsen des übergebenen Contents zur Disposition: Der aus Sicht von PHP am aufwändigsten zu implementierende Ansatz dürfte das Zerteilen des Dokumentquelltextes mit regulären Ausdrücken sein. Hierbei leisten die in HTML verwendeten Tags mit ihren spitzen Klammern gute Dienste. Da den Regular Expressions aber jegliches Wissen über HTML-Strukturen fehlt, muss dieser Mangel vom Entwickler ausgeglichen werden – ein aufwändiges Unterfangen, will man nicht nur auf Sicherheit der Eingaben prüfen, sondern auch noch syntaktische Unsauberkeiten korrekt abfangen.

Wer diese Toleranz nicht walten lassen will – schließlich deutet ein HTML-Fehler auf eine versuchte Manipulation des Benutzers hin – kann sich auch bei den XML-Funktionen von PHP bedienen. Dank der Fähigkeit der LibXML, sowohl HTML- als auch XML-Dokumente zu verarbeiten, erhalten Sie so automatisiert eine leicht zu verarbeitende DOM-Struktur, deren Inhalt rekursiv durchlaufen und gefiltert werden kann. Doch es geht auch ganz klassisch: Wer die HTML- beziehunsgweise XML-Struktur ereignisgesteuert verarbeiten will, kann auf die altbekannte SAX-API von Expat zurückgreifen, die für das Öffnen, den Inhalt sowie das Schließen eines Tags jeweils ein Ereignis auslöst und die zugeordnete Benutzerfunktion aufruft.

PEAR: HTML_safe und SAFE_HTML

Das PEAR-Paket HTML_SAFE [1] setzt zum Parsen das HTML_SAX-Modul ein. Das unter PHP 4 und 5 verwendbare Modul bietet neben der Blacklist-Filterung auch eine saubere Whitelist-Implementierung. Wer bereits mit PEAR arbeitet und im späteren Verlauf keine DOM-Strukturen benötigt, der hat mit dieser Klasse eine leicht zu implementierende API, um sicher zu stellen, dass kein Schadcode in eingehendem HTML versteckt werden kann. Wer PEAR nicht mag, die Klasse allerdings dennoch ausprobieren möchte, der kann zur verwandten Klasse SAFE_HTML [2] greifen: Die vom selben Autor unabhängig angebotene Klasse ist funktionell identisch und in großen Teilen Code-gleich. Die notwendigen Abhängigkeiten aus PEAR wie den HTML-SAX-Parser bringt das Paket gleich mit, so dass dem sofortigen Einsatz nichts entgegen steht.

Aufgrund der Verwendung von SAX, dem Event-basierten Parsing von XML und XML-ähnlichen Strukturen wie HTML, sind SAFE_HTML und HTML_SAFE ideal geeignet, um auch syntaktisch fehlerhaften Quelltext zu verarbeiten.

HTML Purifier

Beim Blick in den Quellcode von HTMLPurifier [3] fällt schnell auf, dass das Projekt um einiges komplexer ist als die PEAR-Variante. Doch auch wenn die Entwickler massiv die Möglichkeiten der OOP einsetzen, um ein hoch flexibles System zur Filterung und Validierung zu erhalten, so ist die Verwendung des ganzen in der Praxis doch ähnlich einfach wie bei den beiden Vorgängern. Mit der Option, das ganze System um Plugins zu erweitern und somit eigene, proprietäre HTML-Erweiterungen zuzulassen, hebt sich HTML Purifier jedoch klar von SAFE_HTML und HTML_SAFE ab.

Wie viel mehr HTML Purifier bietet, zeigt auch, dass zum Parsing der HTML-Rohdaten dem geneigten Anwender gleich mehrere Varianten angeboten werden: Es kann das bereits bekannte SAX eingesetzt werden, eine vollständig eigene Parser-Implementierung oder ab PHP 5 auch der eingangs erwähnte DOM-Parser der LibXML. Zählt man noch die enthaltene Validierung und Säuberung der CSS-Attribute dazu, so erhält man mit dieser Klasse ein sehr leistungsfähiges und sicheres Framework zur Verarbeitung von HTML 4 und XHTML, jeweils in den Ausprägungen strict und transitional.

fDomDocument

Ursprünglich als Teil des freien Site Systems fCMS [4] angebotenen, handelt es sich hier um eine Erweiterung für die Klasse DomDocument in PHP 5.2 und höher und somit eine auf LibXML aufsetzende Implementierung. Neben einigen kleineren Hilfsfunktionen und Erweiterungen, die das Leben mit DOM auch unabhängig vom Site System noch ein wenig angenehmer gestalten sollen, wurde auch eine generische Filter- und Validierungsfunktionalität umgesetzt. Mit dieser lassen sich neben XHTML auch beliebige eigene XML-Derivate prüfen und bereinigen. Bedingt durch den Ansatz als Erweiterung einer DOM-Struktur ist das System nur bedingt fehlertolerant. Diesen Nachteil wiegt die einzigartige Möglichkeit auf, auch Mixed-Content zu verarbeiten: Über die Registrierung von Handler-Klassen je existierendem Namespace lassen sich in XHTML eingebundene SVG-Strukturen ebenso prüfen und filtern, wie MathML oder XUL. Ist keine Klasse für einen Namespace registriert, werden deren Elemente samt Unterknoten aus dem Dokument entfernt. Die aktuelle Version bietet noch keine CSS-Filter, sodass von fDomDocument::cleanup() jegliche style-Attribute in HTML-Dokumenten direkt gelöscht werden. Auf der Projektseite wird ein derartiger Filter aber bereits angekündigt. Die Klasse können Sie dank der Freepoint Public License sehr flexibel in eigene, auch kommerzielle Projekte einbinden.

Geschmackssache

Betrachtet man die Ergebnisse der jeweiligen Filter- und Validierungsansätze, so kann man klar erkennen, dass alle Lösungen die im Beispiel eingebauten gefährlichen Elemente entweder entschärft oder vollständig entfernt haben. Wichtigster Unterschied: Während fDomDocument ein grundsätzlich vollständiges Dokument zurückliefert, reduzieren sowohl HTML Purifier als auch Safe_HTML/HTML_Safe das Beispieldokument auf die ungefährlichen Teile des Body-Elements. Je nach Einsatzbereich kann dieses Vorgehen wie so häufig in der IT-Welt seine Vor- aber auch deutliche Nachteile haben. Selbstverständlich könnte man bei der Verwendung der DomDocument-Struktur auch explizit den Inhalt des Bodys via

$dom->getElementByTagName('body')->item(0)->saveXML();

ausgeben lassen, so dass dieser Ansatz deutlich flexibler verwendet werden kann.

Gilt es im HTML-Dokument enthaltene (ungefährliche) CSS-Angaben zu erhalten, führt zur Zeit noch kein Weg am HTML Purifier vorbei. Für alle anderen Fälle leistet auch das PEAR/HTML_SAFE-Gespann gute Dienste.

XSS-Spielarten

Cross-Site-Scripting (XSS) ist die am häufigsten unterschätzte Gefahr für die Sicherheit vieler Internet-Projekte. Über mangelhaft oder oft gar nicht validierte Eingaben lassen sich in Webseiten eigene Code-Fragmente einschleusen und ausführen. Was beim privaten Gästebuch vielleicht noch als ärgerlich durchgeht, wird spätestens beim Online-Banking oder für Wirtschaftszeitungen zum Problem. Denn neben dem reinen Image-Schaden für den Betreiber sind durch derartige Manipulationen auch schnell weitergehende Schäden verursacht. Dabei muss, wie häufig angenommen, keineswegs vom Benutzer ein manipulierter Link explizit aufgerufen werden. Durch das Einbetten derartiger Links in Foren, RSS-Feeds oder eigenen Seiten lässt sich eine derartige Lücke genauso ausnutzen. Grundsätzlich sind zur Zeit drei verschiedene Arten von Cross-Site-Scripting-Lücken bekannt: Die erste Form tritt nur in lokalen Umgebungen auf. Hier wird eine – z.B. aus der URL selbst stammende – Information ungefiltert in einem lokalen Javascript-Prozess verwendet und zum Beispiel im Browser angezeigt. Eine Interaktion mit einem Server-Backend findet nicht statt. Die zweite Form stellt die mit Abstand größte Menge der XSS-Lücken dar und tritt häufig in Such- und Kontakt-Formularen auf. Da diese XSS-Lücken zwar über manipulierte Eingaben ausgenutzt, die Angaben aber im Regelfall nicht für andere Benutzer sichtbar gespeichert werden, spricht man hier von nicht-persistenten Lücken. Zu guter Letz bleiben noch die persistenten Lücken: Hier werden Benutzereingaben direkt auf dem Server zur späteren Anzeige auch für andere Anwender vorgehalten. Beispiele sind Foren und Gästebücher. Gerade hier wird es durch manipulierte Links leicht möglich, Angriffe auf Webseiten durchzuführen, die über nicht-persistene Lücken verwundbar sind.

Arne Blankerts (theseer@php.net) ist Leiter der Entwicklung bei der NonFood Werbeagentur Unit 2 GmbH in Hamburg und dort unter anderem auch für die Konfiguration der Produktivrechner verantwortlich.

In eigener Sache: Im Entwickler Magazin 1.2008 finden Sie ein Websecurity-Special mit Praxisartikeln und Trend-Themen rund um sichere Webanwendungen und den Schutz und die Analyse Ihrer Server und Quellcodes.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -