Typische Fehler bei der Webentwicklung

Hack me!
Kommentare

Die Zeiten des statischen Webs sind lange vorbei und somit auch die Zeiten, in denen man sich um das Thema Sicherheit bei der Entwicklung drücken konnte – sollte man jedenfalls meinen. Ein Blick auf die Realität zeigt jedoch, dass dem leider nicht so ist und es vor allem viele vermeidbare Fehler sind, die dem Web-Entwickler zum Verhängnis werden.

Jeder macht gelegentlich Fehler. Im Vergleich zu früher, als die meisten Entwickler wohl am Anfang ihrer Karriere mit (Visual-) Basic oder Turbo Pascal programmiert haben, sind Fehler heute leider oft deutlich fataler. Denn hat die ersten Gehversuche beim Entwicklen eines kleinen Tools noch kein weiterer Mensch zu sehen bekommen, werden Webseiten heute gleich einer breiten Öffentlichkeit vorgestellt. Gepaart mit einem gefährlichen Halbwissen über Abläufe im Internet und ausgerüstet mit dem Wissen aus dutzenden unbrauchbaren Tutorials, wird fleißig eine Sicherheitslücke an die andere gereiht. Programmiersprachen wie PHP, die den Eindruck erwecken und leider auch fördern, dass jeder ohne viel Vorwissen programmieren kann, tun dazu ihr übriges. Doch die Schuld alleine bei einfach zu erlernenden Skriptsprachen zu suchen, wäre falsch. Die konzeptionell gleichen Fehler sind auch in Java- oder .NET-Anwendungen zu finden, obgleich diese Sprachen eine erkennbar höhere Einstiegsschwelle aufweisen.

Feindesland

Dabei müsste die Situation gar nicht so traurig sein, wie es sich in der Praxis zur Zeit darstellt. Eine gesunde Paranoia hat noch keinem Entwickler geschadet. Und wenn Politiker auch sonst viel Unsinn reden, mit einem haben sie – vermutlich sogar ohne es zu wollen – klar recht: Das Internet ist böse. Auch wenn die Politiker augenscheinlich eine andere Form des Bösen meinen, so hilft einem beim Entwicklern sicherer Anwendungen diese Einstellung ungemein weiter: Jede Eingabe, jeder Datei-Upload, ja jeder Seitenabruf ist potentiell erstmal ein Hacker-Angriff: Schuldig, bis das Gegenteil bewiesen ist. Was im Umgang mit Mitmenschen undenkbar ist, stellt in der IT-Sicherheit bei der Verarbeitung von Daten aus externen Quellen eine Grundregel dar. 

Den wohl mit Abstand „beliebtesten“ Fehler, die direkte Ausgabe von Benutzereingaben auf Folgeseiten, findet man auf nahezu allen angreifbaren Webseiten. Dabei spielt es erschreckenderweise kaum eine Rolle, ob dies Portale von Fernsehsendern, Webangebote großer Warenhäuser oder die mehr oder minder persönlichen Webseiten von Hobby-Entwicklern sind. Eine Manipulation von Hobbyseiten durch Dritte mag noch als witzig durchgehen, eine bewusst lancierte Falschmeldung auf einem Nachrichtenportal oder vermeintliche Schnäppchen-Preise aufgrund manipulierter Anzeigen beim Webshop stellen für alle Beteiligten jedoch ein unter Umständen kostspieliges Ärgernis dar.

Doch wo genau liegt eigentlich der Fehler? Viele Webentwickler vertrauen scheinbar darauf, dass Benutzer nur sinnvolle Eingaben tätigen, allenfalls das Fehlen einer Eingabe wird noch abgefangen. Doch so eine Eingabe, wenn sie denn stattfindet, kann natürlich zum Beispiel neben einem Suchwort auch HTML-Quelltext enthalten. Wird auf der Trefferseite die vermeintlich sinnvolle Eingabe des Besuchers direkt wieder ausgegeben, so werden vom Browser die enthaltenen HTML-Anweisungen natürlich ebenfalls ausgewertet. Ist es einem Angreifer möglich, auch Skript-Anweisungen auf diesem Weg zu übermitteln, steht einer vollständigen Übernahme der attackierten Webseite nichts mehr im Wege. Das Ergebnis sind neben vielleicht nur scherzhaft abgewandelten Originaltexten durchaus auch handfeste Manipulationen bis hin zu vollständig gefälschten Nachrichten. Dabei ist selbst für erfahrene Surfer nicht unbedingt immer direkt erkennbar, ob es sich um eine via Cross Site Scripting (XSS) manipulierte Seite handelt oder nicht. Zu vielfältig sind heute die Möglichkeiten, eine Manipulation hinter einer langen URL, Weiterleitungen oder eingebetteten Iframes zu verbergen. Besonders spannend wird es, wenn mehrere Webseiten im Verbund gleichartig virtuell verändert werden und sich so durch direkte Verlinkung gegenseitig zu bestätigen scheinen. Auch das vermeintliche Hindernis, dass eine derart manipulierte Seite nur über einen passend manipulierten Link erreichbar ist, stellt in der Praxis kein wirkliches Problem dar – oder überprüfen Sie jeden Link im Vorfeld auf eventuell offensichtlich unpassende Sonderzeichen, bevor Sie ihn anklicken?

Doch es geht auch Nachhaltiger: Denn zu den virtuellen, nur zur Laufzeit via Javascript ausnutzbaren Cross-Site-Scripting-Lücken gesellen sich gern auch ähnliche Lücken in Gästebüchern und Foren. Besonders praktisch an diesen Lücken ist, dass ein Angreifer seine Opfer nur noch auf die Original-URL der Website verweisen muss – die Manipulation der aufgerufenen Seite hinter der Adresse ist ohne Code-Analyse nicht zu erkennen. Hat die Verbreitung von Gästebüchern auf professionellen Webseiten in der Vergangenheit merklich nachgelassen, so sind Foren noch immer ein sehr beliebtes Medium zum Austausch von Meinungen oder zur Abwicklung von Support-Tätigkeiten. Gerade in diesem Umfeld, wo gerne auch unbedarfte Anfänger posten, ist es wichtig, Daten vor der Ausgabe und bei der Speicherung sauber zu validieren. 

Was aber genau ist zu tun? Zunächst gilt es zur prüfen, ob in dem übergebenen Datenstring überhaupt HTML-Quelltext erlaubt sein muss. Ist dies, zum Beispiel bei einer Suchmaske, nicht der Fall, kann schon einmal ein Großteil der möglichen Angriffsvektoren dadurch verbaut werden, dass einfach sämtliche in Tags gefassten Zeichenketten entfernt werden. In PHP erledigt das beispielsweise die Funktion strip_tags(). Man könnte jetzt natürlich argumentieren, dass das Herausfiltern von Teilbereichen einer Eingabe einen unnötigen Eingriff in die Kommunikation darstellt, schließlich wird hier die Aussage eines Benutzers vom Server manipuliert und könnte ja auch durchaus als Beispiel für eine HTML-Frage gemeint gewesen sein. Diesem Gedanken folgend, bietet sich eine gegebenenfalls passendere Vorgehensweise an: Anstatt Tag-artige Strukturen aus dem String zu entfernen, werden diese einfach dadurch entschärft, dass die für HTML notwendigen spitzen Klammern in Entities umgewandelt werden. Bei der Ausgabe im Browser erscheint dann der vermeintliche Quelltext als ganz gewöhnlicher Inhalt – ohne eine Gefahr für Browser, Sicherheit oder Surfer. Wer sein HTML zudem zum strengeren XHTML-Standard kompatibel halten will, muss obendrein dafür sorgen, dass alleinstehende &-Zeichen ebenfalls durch das passende Entity (&) ersetzt werden, da sonst die XML-Parser auf die Nase fallen.

Ist hingegen eine Weiterverarbeitung von HTML notwendig, müssen aufwändigere Maßnahmen zur Validierung ergriffen werden: Ein HTML-Filter muss her. Im PHP-Umfeld gibt es für diesen Einsatzbreich eine ganze Reihe Implementierungen, von denen HTML-Purifier [1] eine der ausgereiftesten darstellt. HTML-Purifier verarbeitet HTML auf eine Weise, die sicher stellt, dass am Ende nur ungefährliche Formatierungs- und Gliederungsstrukturen übernommen werden. Dabei werden sowohl die HTML-Tags und -Attribute gesäubert als auch CSS- und Style-Angaben von allem befreit, was potentiell missbraucht werden könnte. Ein guter HTML-Cleaner geht dabei anhand einer Whitelist vor, das heißt, es werden nur die Elemente und Attribute zugelassen, die als ungefährlich bekannt sind.

Aufmacherbild: Safety concept: circuit board with Metal Contoured Shield icon, 3d render von Shutterstock / Urheberrecht: Maksim Kabakou [ header = Seite 2: Angriff auf die Datenbank ]

Angriff auf die Datenbank

Nachdem der übergebene (Such-) String jetzt aus HTML-Sicht ungefährlich ist, bleibt eine mögliche Gefahrenquelle noch unberücksichtigt: Die Datenbank. Egal ob Login, Suchanfrage oder einfach nur zum Abruf von Content: Datenbanken sind das Herzstück vieler Websites und die Basis für die Erzeugung dynamsiche generierter Inhalte zu erzeugen. So kommt kaum ein CMS, Forum oder Web-2.0-Portal ohne Datenbank zur Verwaltung von Nutzern, Beiträgen und Inhalten aus.

Doch auch eine SQL-Anfrage an die Datenbank ist nüchtern betrachtet nur Text mit einer mehr oder weniger einfachen Syntax, die ein Angreifer durch das Hinzufügen von Informationen mit Leichtigkeit zu eigenen Zwecken verbiegen kann. Häufig sind die so genannten SQL-Injections für den Laien schwerer auszunutzen, als die eingangs beschriebenen XSS-Attacken. Eine Anmelderoutine bei fehlender Validierung der Eingaben auszuhebeln, ist jedoch auch ohne Kenntnisse über die dahinterliegende Datenbankstruktur und somit auch für Anfänger möglich. 

Die gebräuchlichste Form einer SQL-Abfrage zum Login ist eine einfache Anfrage in der Form Select * from benutzer where name=’user‘ and passwort=’geheim‘

Anstelle der hier hartkodierten Angaben treten in realem Code natürlich die Variablen aus der Benutzereingabe. Wird jetzt vom Benutzer statt des regulären Passwortes hier ‚  or 1 übergeben, ergibt sich bei fehlender Validierung oder Vorverarbeitung eine drastisch veränderte Abfrage: Select * from benutzer where name=’user‘ and passwort=“ or 1

Faktisch ist das Login damit ausgeschaltet, denn der Zugriff auf den geschützten Bereich ist aufgrund der Veränderung ohne die Angabe eines Passworts möglich geworden. Wird statt des Passworts der Wert für den Benutzernamen manipuliert, könnte – je nach weiterer Verarbeitung – auch die Anmeldung vollständig übergangen werden. 

So einfach die Abfrage von einem Angreifer zu übernehmen ist, so leicht lässt sich ein derartiger Versuch unterbinden. Für klassische PHP-Entwickler mit MySQL reicht ein einfacher Aufruf von $mysqli->real_escape _string(…) respektive mysql_real_escape_string() unter PHP 4. Auch Anwender von PHP Data Objects (PDO) sind mit $pdo->quote(…) sicher versorgt, wenn SQL-Anfragen von Hand zusammengebaut werden. Vom Konzept her eleganter und in Java-Entwicklungen Gang und Gebe ist die Verwendung von so genannten Prepared Statements. Derartig definierte Anfragen sind nicht nur eleganter, sondern auch deutlich sicherer: Durch typsichere Platzhalter, die zur Laufzeit mit Benutzereingaben befüllt werden, ist eine Manipulation selbst mit den abstrusesten Werten ausgeschlossen. Das Ausbrechen aus den Anführungszeichen, die den Wert umschließen sollen, wird durch Escaping automatisch verhindert. Auf diese Weise sind auch echte Zahlwerte im Query möglich, da die Datenbank-Objekte bei der Übergabe eines Strings diesen in eine Zahl passenden Formats umwandeln oder bei typsicheren Sprachen wie Java deren Verwendung ablehnen. 

Natürlich ist die Umgehung eines Logins nur eine von vielen Möglichkeiten, die einem Angreifer mit SQL-Injections zur Verfügung stehen: Das Ausspähen von Daten, Einfügen manipulierter Datensätze und nicht zuletzt das Löschen von Einträgen sind nur ein kleiner Teil dessen, was aufgrund ungenügender Absicherung alles möglich ist. Mit ausreichenden Rechten auf der Datenbank ausgerüstet, könnten von einem Angreifer sogar externe Prozesse ausgeführt oder weitere Accounts angelegt werden.

Weltoffen

Bei der Entwicklung von Webseiten dauert es in der Regel nicht lange und der emsige Programmierer erkennt, dass er eine Website hervorragend durch eine einzelne Kontrolldatei steuern kann. Einzelne Seitenteile werden dann je nach Bedarf nachgelanden und machen so das Überarbeiten unzähliger Dateien im Falle einer Änderung überflüssig. Ein schöner und praktikabler Ansatz – wenn man weiß, was man da eigentlich tut.

Nur allzu oft werden Angaben aus der URL direkt in lokale Pfade umgesetzt, so dass einem Angreifer bei der Manipulation der Parameter praktisch alle auf dem Server befindlichen Dateien offen stehen. Besonders spannend wird dies vor allem dann, wenn auf dem betroffenen Server PHP eingesetzt wird, die Option, Skripte auch von entfernen Adressen zum Beispiel via HTTP nachzuladen, nicht deaktiviert ist und der Entwickler eine Überprüfung des gewünschten Pfades vergessen hat. Wird der so über einen weiteren Server eingeschleuste Inhalt vom eigentlichen Skript via include oder require angefordert, hat ein Angreifer praktisch alle Rechte auf dem System: Er kann beliebige Dateien anlegen, ändern oder löschen, Datenbanken auslesen und löschen, sowie natürlich existierende Inhalte verändern. 

Wer beim Einsatz von PHP auf derartige Spielereien verzichten will und kann, der deaktiviert die Option allow_url_include in der php.ini. Alternativ oder auch zusätzlich kann die Option allow_url_fopen gesperrt werden – dann ist via PHP auch im sonstigen Umfeld das Öffnen von Dateien auf entfernten Systemen nicht mehr möglich. 

So praktisch diese Optionen wirken mögen, sie entlassen selbstverständlich den Entwickler nicht aus der Pflicht, Pfadangaben ständig vor dem Einsatz zu validieren. Wird dies vernachlässigt, so ist es einem böswilligen Besucher unter Umständen möglich, beliebige andere Dateien auf dem Server einzusehen. Neben Passworten und Datenbank-Zugängen sind so auch weitere interne Details der Datenstruktur heraus zu bekommen. Pikant wird das ganze dann, wenn die Webseite es einem Benutzer erlaubt – zum Beispiel im Rahmen eines Profils – eigene Dateien zu übertragen. Werden diese Dateien in einem für den Benutzer erratbaren, lokalen Pfad abgelegt, so lassen sich diese mit hoher Wahrscheinlichkeit ebenfalls als Include über einen angepassten Parameter einbinden. Ist der zur Speicherung der Upload-Dateien verwendete Pfad zudem sogar noch direkt von außen erreichbar, hat der Angreifer bereits gewonnen: Er kann beliebige Skripte hochladen und nach eigenem Ermessen auf dem Server ausführen. Es bietet sich daher mehr als an, vom Benutzer eingespielte Daten nach der Verifizierung durch einen aktuellen Virenscanner in einem nicht direkt von Außen zugänglichen Bereich abzulegen und idealerweise den Zugriff selbst nur über ein Mapping zu ermöglichen. 

Überhaupt sind Whitelisten immer eine gute Idee, wenn es darum geht, durch Benutzer oder Links übergebene Parameter auf Einträge in einer Datenbank, im Dateisystem oder in anderen Medien zu verweisen. Dies erfordert zwar ein wenig mehr Arbeit als das direkte Verwenden von Nutzereingaben, ist dafür aber in der Praxis kaum zu hacken.

Fazit

Die vorgestellten Beispiele dürften es gezeigt haben: der überwiegende Teil an Sicherheitsproblemen wird durch mangelnde Sorgfalt bei der Validierung verursacht. Und auch wenn es kein Allheilmittel gibt, so hält sich der Aufwand zur Absicherung von SQL-Abfragen, HTML-Ausgaben oder dem Aufruf von externen Prozessen doch in überschaubaren Grenzen. Wer zudem ständig wiederkehrende Aufgaben in auf Sicherheit optimierte Funktionen oder Klassen auslagert, spart in der täglichen Arbeit gleich doppelt: Zum einen kann bei der Entwicklung neuer Webseiten und Anwendungen auf bereits geleistetes aufgesetzt werden, zum anderen bedarf es bei eventuell notwendigen Verbesserungen nur an wenigen Stellen im Quelltext einer Optimierung.

Wird dann noch bei der Wahl einer Ordnerstruktur der Aspekt der Sichtbarkeit von Außen und damit der Sicherheit der enthaltenen Dateien beachtet, steht einem gelungenen Webauftritt eigentlich nichts mehr im Wege.

Problemkind Internet Explorer

Auch wenn fast alle hier gezeigten Sicherheitsprobleme eigentlich serverseitg zu lösen sind, so verschärft der Internet Explorer die meisten Angriffsvektoren, indem er auch an den unerwartetsten Stellen JavaScript oder JScript interpretiert und ausführt. So wurde in Sicherheits-Mailinglisten unter anderem davon berichtet, dass der Microsoft-Browser selbst den in Grafiken eingebetteten JScript-Quelltext ausführt. Es reicht für den IE daher nicht aus, durch Benutzer übertragene Dateien als gültige PNG-, JPG- oder GIF-Datei zu identifizieren. Der Entwickler muss außerdem – zum Beispiel durch Skalieren – sicher stellen, dass kein unerwarteter Skriptcode mehr enthalten ist.

Die Eigenart des IE, auch aus dem krudesten Code-Wirrwar noch etwas Brauchbares herausparsen zu wollen, führt in der Praxis zu weiteren Problemen: Nämlich immer dann, wenn der Browser meint, schlauer sein zu müssen, als der Webserver, der einen Content-Type vorgegeben hat, der IE diesen aber zugunsten seiner eigenen Erkennung ignoriert. Auf diese Weise lassen sich gezielt für den IE Exploits entwickeln, die bei anderen Browsern einfach nur zu einer defekten Datei im Download führen.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -