SQL-Injections

14. August 2011
Von

Neben XSS-Angriffen gehören SQL-Injektionen zu Standardangriffen, gegen den jedes PHP-Skript abgesichert sein sollte. Auch hier liegt die grundlegende Schwachstelle im Code selbst, genauer: bei der Parameterüberprüfung.

Wie der Name es bereits sagt, versuchen Angreifer bei einer SQL-Injektion, fremden (= ihren eigenen) SQL-Code einzuschleusen. Die Auswirkungen davon können verheerend sein: Ein Beispiel dafür ist der direkte Log-In als Administrator, ohne das korrekte Passwort zu kennen:

<h1> Administrationsbereich </h1>
<form action="" method="POST">
    Nutzer: <input type="text" name="user" /> <br />
    Pass: <input type="password" name="pass" /> <br />
    <input type="submit" name="login" value=“login“ />
</form>
<?php
if (isset ($_POST['login']) )
{
    $res    =   mysql_query ("SELECT * FROM admins WHERE
nutzer='".$_POST['user']."' AND
pass='".md5($_POST['pass']).“'“); $rows = mysql_num_rows ($res); if ($rows == 1) { echo "Erfolgreich eingeloggt!"; } }
?>

(Man beachte die Nutzung von MD5-gehashten Passwörtern, dies ist ein weiterer strenger Sicherheitstipp; niemals Passwörter im Klartext in der Datenbank speichern! Am besten auch zusätzlich noch salten oder mehrere Algorithmen hintereinanderschalten.)

Nehmen wir an, ein valides Administrationskonto besteht aus dem Nutzernamen „admin“ und dem Passwort „login“. Der Angreifer, der eine SQL-Injektion ausführen möchte, kennt zwar den Nutzernamen (dieser wird überall öffentlich genannt), nicht aber das geheime Passwort. Da er allerdings eine Query-Formulierung wie die obige vermutet, in denen die POST-Parameter ungefiltert und ungeprüft übergeben werden, wählt er als Benutzernamen nicht „admin“, sondern „admin’#“ (admin / Raute / einfacher Anführungsstrich). Ein Passwort gibt er gar nicht ein.

Der Query, der abgeschickt werden würde, sähe demzufolge so aus:

SELECT * FROM admins WHERE nutzer='admin'#'
AND pass='d41d8cd98f00b204e9800998ecf8427e'

Wichtig hierbei: Das Raute-Zeichen zählt innerhalb eines SQL-Kommandos als Kommentar – der hintere Teil des Querys würde also wegfallen, hier blau markiert:

SELECT * FROM admins WHERE nutzer='admin'#'
 AND pass='d41d8cd98f00b204e9800998ecf8427e'

Es handelt sich also um einen validen Query, der nach einem Eintrag sucht, in dem der Nutzername „admin“ entspricht – nach dem Passwort wird gar nicht mehr gefragt. Dies funktioniert jedoch nur, weil der Angreifer den zu überprüfenden String mit einem ‘ abbricht und mit einem Kommentarzeichen sowohl SQL-Fehler als auch die weitere Überprüfung umgeht.

Solche Zeichen, die in SQL eine spezifische Bedeutung haben und Querys manipulieren können, müssen also entsprechend umgewandelt bzw. gefiltert werden. Dafür steht in PHP die Funktion „mysql_real_escape_string“ zur Verfügung, die immer ausgeführt werden sollte, wenn ein String in einem Query eingebunden wird.

Für obiges Beispiel resultiert so:

<h1> Administrationsbereich </h1>
<form action="" method="POST">
    Nutzer: <input type="text" name="user" /> <br />
    Pass: <input type="password" name="pass" /> <br />
    <input type="submit" name="login" value=“login“ />
</form>
<?php
if (isset ($_POST['login']) )
{
    $res = mysql_query ("SELECT * FROM admins WHERE
        nutzer='".mysql_real_escape_string($_POST['user'])."'AND
        pass='".md5($_POST['pass']).“'“);
    $rows   =   mysql_num_rows ($res);
    if ($rows == 1)
    {
        echo "Erfolgreich eingeloggt!";
    }
}
?>

(Bei Übergabe des Passwortes ist dies nicht notwendig, da der String bereits als MD5-gehashed wird und somit keine Sonderzeichen aufweisen kann!)

Dieses Beispiel ist allerdings nur eine mögliche Version eines Angriffes mit einer SQL-Injection. Diese sind sehr vielseitig und so sind auch das Auslesen von Daten aus der Datenbank, hochladen von Dateien auf den Server (INTO OUTFILE) oder der Absturz des Datenbankservers (BENCHMARK) als Angriffsszenarien möglich.

Fazit: Never trust user input!

Ähnliche Artikel:

  1. Cross-Site Scripting

Tags: , ,

4 Responses to SQL-Injections

  1. Tobsen zu 15. August 2011 auf 07:19

    Oh man immer mit den Usereingaben rumhantieren, keine gute Idee… :)
    Aber danke für das anschauliche Beispiel, dass alleine schon ein ‘# reichen würde um die Passwortabfrage zu umgehen, wenn mal wieder ein Anfänger am Programmieren war. :)

    Ich hoffe mal, dass dies bei WordPress nicht mehr der Fall ist. :)

    • admin zu 15. August 2011 auf 17:56

      Nein bei dem WordPress-Login ist dies nicht der Fall. Allerdings muss man auch immer auf die Plugins achten, damit kann man sich nämlich auch unbemerkt Schwachstellen reinholen.

  2. Andrew zu 19. August 2011 auf 21:42

    Besser ist es wenn man md5+salt nutzt. Damit beugt man rainbow tabellen etwas vor, falls doch mal jemand die Datenbank bekommen sollte. also md5( $pass . ‘salt_38374ojkdaskldjlaskjdlu08u23jkl’ )

  3. [...] Was ist eine SQL Injection? [...]

Hinterlasse einen Kommentar zu Tobsen Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

*

eMail-Benachrichtigung bei weiteren Kommentaren.
Auch möglich: Abo ohne Kommentar.

Finde mich auf

Werbung