Webserver absichern
Angriff-Code für Datenbanken
Cross-Site-Scripting
Webserver absichern
Die beiden interessantesten Angriffsarten für Web-Cracker heißen Cross-Site-Scripting und SQL-Injection: Diese Methoden mit ihren zahlreichen Variationen sind hauptsächlich für Sicherheitsprobleme in Webseiten verantwortlich. Vermeidet der Administrator Fehler, die solchen Attacken Angriffsfläche bieten, und führt er zudem alle Sicherheitswartungen am System und den Webanwendungen regelmäßig durch, befindet er sich auf der sicheren Seite. Bei einem Angriff auf eine Webanwendung muss nicht immer der Betreiber der Webseite der Angegriffene sein. Auch die Benutzer einer Webanwendung können leicht zu Opfern werden. Selbstschutz und Schutz der Anwender ist aber relativ einfach zu realisieren ? sowohl gegen Cross-Site-Scripting (XSS) als auch gegen SQL-Injection.
Besucher ausspionieren
Mit Cross-Site-Scripting versucht der Angreifer, den Benutzer einer Webseite auszuhorchen. Abgesehen hat es der Übeltäter auf sensible Informationen wie Passwörter oder Kreditkartendaten. Dazu gaukelt der Angreifer dem Benutzer vor, er sähe Inhalte der Webseite, die er gerade (vermeintlich) besucht. Tatsächlich schiebt der Cracker dem Besucher jedoch eine gefälschte Seite unter, die neben den sichtbaren Inhalten häufig auch Skripte in Javascript oder anderen Sprachen enthält. Diese Skripte fangen nun Informationen ab, die der Besucher nicht freiwillig hergeben würde. Der Begriff Cross-Site-Scripting hat sich für eine Fülle von Angriffen etabliert, obwohl häufig weder Skripte noch verschiedene Websites involviert sind. Bekannt ist Cross-Site-Scripting schon lange. Bereits im Jahre 2000 veröffentlichte das CERT einen Beitrag, der die Problematik erläutert. Viel geändert hat sich allerdings seitdem nicht. Praktisch jede Woche tauchen neue XSS-Angriffsflächen in kommerziellen und nicht-kommerziellen Webanwendungen auf. Betroffen ist unter anderem das weit verbreitete Portalsystem PHPNuke (phpnuke.org), mit dem viele Webseitenbetreiber ihre dynamischen Seiten ausliefern und gestalten.
XSS: die Grundlagen
Webserver absichern
Beim XSS macht sich der Angreifer die Vertrauensstellung zwischen dem Angegriffenen und der von ihm besuchten Webseite zu Nutze. Der Spion schaltet sich per Skript dazwischen und fängt die Daten ab. Webseiten enthalten sowohl statischen Text als auch Anweisungen in Hypertext Markup Language (HTML). Beides generiert der Webserver und sendet die Daten an den Client-Browser. Erzeugt der Server statische Seiten, dann hat er auch die volle Kontrolle darüber, wie der Client-Browser diese Seiten interpretiert. Nicht so bei Seiten mit dynamischem Inhalt: Hier entscheidet der Client, was er mit den Inhalten anstellt. Per XSS lassen sich nun unsichere Inhalte so in eine dynamische Seite einschmuggeln, dass weder der Server noch der Client etwas davon bemerken. Dadurch können weder Client noch Server passende Schutzmaßnahmen ergreifen. Bei HTML unterscheidet sich Text von den HTML-Anweisungen (Markup) durch spezielle Zeichen. Das Kleiner-als-Zeichen »< « leitet einen HTML-Tag ein. Diesem folgt entweder eine Formatanweisung, zum Beispiel »
« für den Seitenkörper, oder aber sie führen ein Skript per Tag »< script>« aus.Dynamische Seiten
Erzeugt ein Webserver dynamische Seiten, muss der Betreiber sicherstellen, dass die so generierten Inhalte keine speziellen HTML-Zeichen enthält. Ansonsten kann es passieren, dass der Client Teile der Daten der Webseite als HTML-Tags oder Skript interpretiert, statt diese als Text darzustellen, etwa beim Resultat einer Datenbanksuche. Viele Webapplikationen wie beispielsweise Diskussionsforen füttern die Benutzer selbst mit Daten. Die Anwendung speichert die Meinungen in einer Datenbank, arbeitet sie auf und liefert diese dann später an andere Anwender. Allerdings ist ein Angreifer dadurch auch in der Lage, selbst zu bestimmen, welche Daten ein Webserver an andere Anwender ausliefert. Der Angreifer kann versuchen, dem Browser des Anwenders der Webseite ein Skript unterzuschieben. Dieses führt der Browser dann im Sicherheitskontext der Kommunikation mit dem völlig legitimen Webserver aus und nicht im Kontext einer Kommunikation mit dem Angreifer. Das Skript hat also einen unerwünschten Sicherheitskontext und damit auch unerwünschte Privilegien innerhalb des Browsers des Angegriffenen.
Requests per Skript umleiten
Webserver absichern
Auch der Servername im Link ist trügerisch. Der Angreifer kann den Link auch so formulieren, dass die Benutzeranfrage zuerst bei einem Server des Angreifers landet. Dieser wertet die per URL-Parameter übertragene Information aus ? zum Beispiel der Inhalt eines Cookies auf dem Client ? und leitet anschließend den Request an den richtigen Server weiter. Der Benutzer bekommt von der Zwischenvisite nichts mit, da die Antwort ja vom richtigen Server kommt. Aber der Angreifer kann noch gemeiner sein. Das bösartige Skript lässt sich auch von einer anderen Webseite laden. Alles was der Spion dazu braucht, ist ein passend formulierter Link:
Dieser Link ist ein Paradebeispiel für das Cross-Site-Scripting: Eine Seite injiziert Code in eine Seite, die von einer anderen Site stammt.
Per XXS angreifen
Webserver absichern
Nun zu ein paar Beispielen, wie solche Angriffe in der Praxis aussehen. Ein einfaches Ziel ist beispielsweise ein auf HTML basierendes Diskussionsforum im Web. Hier ist die Diskussion nur möglich, wenn ein Anwender Daten für einen anderen Anwender zur Verfügung stellt. Der Angriff gegen ein solches Diskussionforum beginnt ganz harmlos. Der Angreifer veröffentlicht einfach eine Nachricht: »Hallo! Hier eine interessante Nachricht. . Bis bald und viele Grüße!« Der Angreifer bettet in diese Nachricht Skriptcode ein. Lädt ein Clientbrowser mit eingeschaltetem Scripting die Nachricht, dann führt der Client den Skriptcode aus. Der Spion hat sein Ziel somit schon erreicht. Denn der Javascript-Code stammt von der gleichen Site wie die Seite, in die er eingebettet ist. Darum kann der Code nun auch den Inhalt der Seite beliebig verändern. Der Angreifer könnte nun die normale Seite verstecken und stattdessen ein Login-Formular anzeigen. Die erschlichenen Daten lässt er nach der Eingabe durch den arglosen Benutzer an einen seiner Server senden. Dieses Problem kommt nicht nur bei Javascript-Tags vor. Betroffen sind außerdem die Tags »>
Hier klicken
Um die eigenen Anwender vor solchen Angriffen zu schützen, muss der Programmierer einer Webanwendung unsichere Daten, die vom Webserver ausgehen, passend filtern. Derlei böse Daten können aus verschiedenen Quellen stammen. Dazu gehören URL-Parameter, Inhalte von Formularen oder Datenbankabfragen und Cookies.
Böse Daten filtern
Webserver absichern
Um erfolgreiche Angriffe auf Ihre Webserver zu vermeiden, sollten Sie grundsätzlich allen Inhalten von Anwendern misstrauen. Filtern Sie den Datenstrom und lassen Sie lediglich die Daten zu, die ausdrücklich erlaubt und erwünscht sind. Verlangen Sie beispielsweise die Eingabe einer E-Mail-Adresse mit Hilfe eines Formulars, sollte der Webserver nur gültige E-Mail-Adressen zulassen und sonst nichts. Dabei ist es extrem wichtig, dass Sie die eingegebenen Daten nicht erneut anzeigen, falls der Filter diese bemängelt ? auch nicht im Rahmen der Fehlermeldung. Inhalte lassen sich recht simpel mit regulären Ausdrücken (regular expressions) prüfen. Diese erlauben es, Benutzereingaben mit einem Muster zu vergleichen. Stimmen die Angaben nicht, dann soll der Webserver diese ignorieren oder eine entsprechende Fehlermeldung ausgeben: »Ihre Angaben enthalten unzulässige Daten «. Das ist zwar auf den ersten Blick nicht besonders benutzerfreundlich, aber dafür sicher für den Benutzer Ihrer Webanwendung. PHP, Perl oder andere auf Webservern benutzte Sprachen bringen umfangreiche Unterstützung für reguläre Ausdrücke mit. Im Fall von PHP finden Sie die Funktionen rund um reguläre Ausdrücke im Satz der Funktionen, die mit »preg_*« beginnen.
Klammern filtern reicht nicht
Webserver absichern
Kluge Köpfe könnten nun darauf kommen, einfach alle spitzen Klammern zu filtern, um dadurch die < script>-Tags zu eliminieren. Leider reicht dies nicht, denn der Angreifer kommt auch ohne die Klammern aus. Einmal angenommen, Ihr Server verwendet das folgende (vereinfachte) Codefragment: $userName = UserNameFromUserInput(); print '< img src=photo.gif onmouseover=Action("' . $userName . '");>' Der Webserver baut hier eine Seite zusammen, die ein Bild enthält. Fährt der Besucher der Seite mit der Maus über dieses, so wird eine Javascript-Funktion aufgerufen. Hier wird der Username als Parameter übergeben. Der String entspricht dem Benutzernamen des Besuchers, den er selbst eingibt. Nun setzt der Angreifer den Querystring wie folgt:
Paul"); alert(document.cookie)"
Der Webserver baut diesen Querystring zu folgendem Code zusammen:
< img src=photo.gif onmouseover= 'Action("Paul"); alert(document. cookie); '");'>
Bewegt der Besucher den Mauszeiger über das Bild, wird der Inhalt des Cookies per »alert()« angezeigt. Hier im Beispiel ist das nicht dramatisch, denn die Anzeige erfolgt auf dem Rechner des Lesers. Ein Angreifer hätte den Inhalt des Cookies natürlich an seinen eigenen Server gesendet und wäre somit im Besitz der Daten. Das Filtern der Tags hätte nichts gebracht. Statt der speziellen Methode, dynamisch erzeugte Inhalte pro Formularfeld zu filtern, können Sie auch den allgemeinen Weg gehen.
Sofern Sie Daten für eine Webseite verwenden, benutzen Sie die Funktionen »htmlentities()«, »htmlspecialchars()» und »urlencode()«. Diese neutralisieren alle relevanten Zeichen, indem diese escaped werden. Das CERT liefert in einem Advisory zu XSS zudem tiefgehende Informationen unter http://www.cert.org/advisories/CA-2000-02.html.
Angriffsfläche SQL-Injection
Webserver absichern
Anders als beim XSS geht es bei SQLInjection darum, direkt die Datenbank hinter einem Webserver anzugreifen. Als Resultat des Angriffs kann der Angreifer unter Umständen Code auf der Datenbank ausführen, Zugriff auf sensible Daten erlangen oder zumindest Schaden in der Datenbank anrichten. Im Kern ist der Angriff ähnlich wie beim XSS. Das Verfahren basiert darauf, dass der Angreifer passende Daten in den Webserver schmuggelt, indem er Skripte mit ihm genehmen Daten füttert. Das geht meist über Formularfelder wie etwa dem Login-Feld einer Webanwendung. Gelangen die dort eingegebenen Daten ohne Nachbearbeitung in die Datenbank, ist diese per SQL-Injection angreifbar. Das Formular kann etwa so aussehen:
Der passende PHP-Code hätte dann folgenden Aufbau:
$qs = "select count(*) from users where username=$username and password=$password limit 1";
$r = mysql_db_query( "myDatabase", $qs, $connect);
$nr = mysql_num_rows( $r);
Der Code baut zunächst einen SQLString zusammen und führt diesen dann aus. Ob der Anwender einen Benutzernamen sowie ein Passwort angegeben hat, lässt sich an der in »$nr« gelieferten Zahl ablesen. Das Problem liegt hier an ähnlicher Stelle wie beim XSS: Die Benutzereingaben »$username« und »$password« gelangen ungetestet in die Datenbank. Dadurch kann der Angreifer erfolgreich beliebige Texte eintragen, um mit diesen den SQLServer zu manipulieren. Dazu schreibt der Angreifer den folgenden Text als Benutzernamen in das Login-Formular:
' or 0=0 --
Das Resultat ist ein gefährlicher Query- String mit folgendem Code:
select count(*) from users where username='' or 0=0 - - and password= limit 1
Die beiden Minus-Zeichen (- - ) im SQL Query-String kommentieren effektiv den Rest des SQL-Queries aus. Von diesen Zeichen an ignoriert der Server alle weiteren Zeichen im Querystring. Das Select wird also immer wahr. Die Angabe eines leeren Usernamens spielt keine Rolle. Die Gleichung »0 = 0« wird immer wahr und funktioniert aufgrund der »or«-Verknüpfung auch dann, wenn es keinen Eintrag mit einem leeren Benutzernamen gibt. Der String evaluiert also zu true ? der Angreifer hat sich soeben erfolgreich bei Ihrer Anwendung eingeloggt.
Die »gefährlichen« Zeichen wie Kommentare- Symbole und Wildcards sind von Datenbank zu Datenbank verschieden. Das Konzept bleibt hingegen gleich. Auch mag der Angriff auf den ersten Blick noch nicht so schlimm wirken: Was kann der Spion schon tun, schließlich hat er ja keinen Zugriff auf echte Account-Daten.
Sag den Daten leise Servus ...
Webserver absichern
Auf den zweiten Blick sieht die Sache anders aus. Der Angreifer verwendet einen anderen String als Eingabe:
'; drop table users --
Das Resultat ist heftig: Durch das Hochkomma und den folgenden Strichpunkt beendet sich der erste SQL-Befehl ohne irgendwelche Auswirkungen. Mit dem hinter dem Semikolon angefügten SQL-Befehl löscht der Angreifer dann die komplette Benutzertabelle!
Der Übeltäter kann somit zahlreiche weitere solcher Kommandos per SQL an die Datenbank schicken. An einer passenden Stelle eingefügt kommt der Angreifer dadurch leicht an alle Useraccounts einer Webanwendung oder aber er verändert Benutzerdaten. Solchen Attacken den Nährboden zu entziehen ist jedoch recht einfach. Für PHP-Webseiten verwenden Sie die Funktion »mysql_escape_string()«. Damit escapen Sie alle Parameter, die aus Anwendereingaben stammen und die in den MySQL-Query-String eingehen.