21.10.2005, 10:13 Uhr

Hacking per Webbrowser

Egal, wie effektiv die Firewall und wie gut der Virenschutz ist: Die grösste Gefahr für eine Website besteht immer noch aus unbedarften Programmierern.
Wer an einem bestimmten Tag im Mai 2004 einen Blick auf die Homepage von Microsoft Press UK geworfen hat, musste sich verwundert die Augen reiben: Das aktuellste Buch des Verlags hiess «Owned by Outlaw Group». Doch diesen Titel gab es natürlich in keinem Bücherregal zu finden. Stattdessen ist es einem Angreifer einfach gelungen, den Inhalt der Site zu modifizieren, ein so genanntes «Defacement». Dazu war es nicht einmal notwendig, den Server zu knacken und die (wirklich gute) Firewall zu überbrücken. Alles, was der Angreifer gebraucht hat, war etwas Kreativität und ein Webbrowser.
Die im Juli 2004 veröffentlichte Top-Ten-Liste des OWASP (Open Web Application Security Project) [1] veröffentlichte die zehn häufigsten sicherheitskritischen Fehler auf einer Website. Die ersten acht Punkte waren dabei eindeutig auf mangelhafte Programmierung zurückzuführen, lediglich Punkt 9 und Punkt 10 hatten mit der Konfiguration zu tun, so dass hier der schwarze Peter zumindest ein bisschen der Administration zugeschoben werden konnte.
Das Tragische dabei: Die meisten Angriffe laufen immer gleich ab. Und obwohl sich die Angriffsmethoden immer wieder ändern und auch neue Wege gefunden werden, sind es vor allem die alt bekannten Techniken, die eine Website sprichwörtlich alt aussehen lassen. Dabei sind besonders Cross-Site Scripting und SQL Injection zu nennen, die im Folgenden ausführlicher beschrieben werden.
Zunächst aber zum Kern des Problems. Zwei Grundregeln gibt es zu beachten, um eine Website schon bei der Programmierung recht sicher zu gestalten (auch wenn 100-prozentige Sicherheit eine Illusion ist):
- Validieren Sie Eingaben vom Client.
- Entwerten Sie Sonderzeichen, wenn Sie dynamische Inhalte an den Client schicken.
Damit lassen sich schon viele Angriffe abwehren; zwei davon sind besonders weit verbreitet.

SQL Injection

Die meisten Anwendungen verwenden auf SQL-Abfragen, die in Abhängigkeit von Benutzereingaben dynamisch zusammengestellt werden. Am bequemsten - und auch gefährlichsten - ist es, diese Benutzereingaben direkt per String-Konkatenation in das SQL-Kommando zu schreiben. Die folgende Art von Code findet man leider immer wieder:
LISTING 1
SqlConnection conn = new SqlConnection(strConn);
conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = String.Format(
"SELECT id FROM users WHERE user="{0}" AND passwort="{1}"",
TextBox1.Text, TextBox2.Text
);
cmd.Connection = conn;
cmd.ExecuteScalar();
Der Problem mit diesem Code: Benutzer-eingaben werden ungeprüft mitten in das SQL-Kommando eingefügt. So kann eine einfache Login-Maske (Screen) zu einem Angriff missbraucht werden. Wie wäre es beispielsweise mit einem leeren Benutzernamen und diesem Passwort:
LISTING 2
x"; DROP TABLE users; --
Das SQL-Kommando sieht dann wie folgt aus:
LISTING 3
SELECT id FROM users WHERE user="" AND passwort=" x"; DROP TABLE users; --"
Die beiden Bindestriche am Ende stehen im Microsoft SQL Server für einen Kommentar. Das bedeutet, dass der Rest der Abfrage ignoriert wird. Durch dieses spezielle «Passwort» kann also ein Angreifer die Datenbanktabelle löschen, und das direkt über den Webbrowser. Zahlreiche andere Angriffe sind möglich, beispielsweise ein beliebiger Nutzername und das Passwort < OR 2>1--. Das führt zu folgendem SQL-Kommando:
LISTING 4
SELECT id FROM users WHERE user="admin" AND passwort="" OR 2>1 --"
Die Bedingung 2>1 ist immer erfüllt, der Benutzer kann sich also ohne Wissen eines Passwortes einloggen. Immerhin, ASP.NET bietet auch ein probates Gegenmittel an, das gleichzeitig auch noch für eine gute Performance sorgt: Prepared Statements. Überall, wo im SQL-Statement dynamische Inhalte eingefügt werden müssen, steht ein Platzhalter; diese Platzhalter werden dann per Methodenaufruf gefüllt. Die Behandlung «gefährlicher» Zeichen wie eben Apostrophe übernimmt dann ADO.NET. Der folgende Code funktioniert ab Version 2.0:
LISTING 5
cmd.CommandText = "SELECT id FROM users WHERE user=@USER AND passwort=@PASSWORT";
cmd.Parameters.AddWithValue("@USER", TextBox1.Text);
cmd.Parameters.AddWithValue("@PASSWORt", TextBox2.Text);
cmd.Connection = conn;

Cross-Site Scripting (XSS)

Die zweite gefährliche Angriffsmethode hört auf den Namen Cross-Site Scripting, oder kurz XSS. Hier kommt die zweite oben angesprochene Fehlerquelle zum Tragen: Daten, die ohne Prüfung ausgegeben werden. Hier ein kurzer, aber sehr gefährlicher Codeschnipsel:
LISTING 6
<%@Page Language="C#" ValidateRequest="false" %>
Das Problem: Was, wenn ein Angreifer HTML-Markup oder gar JavaScript-Code in das Textfeld eingibt? Zwar bietet ASP.NET seit Version 1.1 eine Möglichkeit an, solche Probleme zu vermeiden. Dabei sorgt das Attribut validateRequest dafür, dass bei spitzen Klammern und direkt danach einem Buchstaben eine Fehlermeldung erscheint. Im Profi-Bereich jedoch wird das meist ausgeschaltet, weil viele Anwendungen (etwa Webmail) spitze Klammern zulassen möchten. Es gibt ebenfalls viele Ansätze, Eingaben zu filtern, aber das XSS Cheat Sheet [2] zeigt mehr Angriffsmöglichkeiten als vorstellbar sind. An dieser Stelle soll nur ein einfacher Angriff gezeigt werden: Die Cookies des Benutzers erscheinen direkt im Browser . Das geht mit folgender Texteingabe:
LISTING 7
Dieser Angriff ist natürlich noch nicht schädlich, aber mit sehr wenig Aufwand ist es möglich, dass dieses Cookie an einen Angreifer weitergegeben wird, ohne dass das Opfer das mitbekommt. Deswegen: Nutzerdaten, die ausgegeben werden, müssen kodiert werden. ASP.NET bietet dazu die Methode Server.HtmlEncode() (ein Alias für HttpUtility.HtmlEncode()), die sogar schon beim klassischen ASP zur Verfügung stand. Damit müssen all diese Daten vorbehandelt werden:
LISTING 8

Fazit

SS und SQL Injection sind zwei sehr simple, aber leider auch sehr gefährliche Angriffsmöglichkeiten. Gerade bei altem Legacy-Code lassen sich mitunter grosse Lücken finden, die diese Angriffe möglich machen. Besonders wichtig ist es, bei neuem Code von Anfang an die Sicherheit im Hinterkopf zu haben. Für grössere Projekte hat Microsoft übrigens den Secure Development Lifecycle (SDL) [3] entwickelt, der ebenfalls zu sicherer Software beitragen kann.
Christian Wenz


Das könnte Sie auch interessieren