SQL Injection
Autor
Flitze
Klicks 30861
Bewertungen 18
Rating 6.6
Stand 18.06.2009
Keywords:
SQL Injection, fremden Code einschleusen, Datenbankabfragen schützen, SQL-Queries sichern, mysql_real_escape_string(), addslashes()
Klicks 30861
Bewertungen 18
Rating 6.6
Stand 18.06.2009
Keywords:
SQL Injection, fremden Code einschleusen, Datenbankabfragen schützen, SQL-Queries sichern, mysql_real_escape_string(), addslashes()
Breadcrumb:
Artikel » SQL Injection
Was ist SQL Injection?
[ADSENSE_LINE]Mit dieser Art der Injection wird man früher oder später konfrontiert, wenn man SQL-Datenbanken benutzt. Dadurch, dass auch ich eine MySQL-Datenbank verwende, stieß ich auch darauf. SQL-Injection nutzt Sicherheitslücken beim Ausführen eines SQL-Queries aus indem zum Beispiel Funktionszeichen in den Query eingefügt werden. Dadurch kann ein Angreifer eigene SQL-Befehle ausführen, wie z.B. das Ausgeben geschützter Systemdaten oder gar der Veränderung von Benutzerrechten, oder er kann schlichtweg den ursprünglichen SQL-Query manipulieren.
' OR '1' = '1
Zur Verdeutlichung nenne ich ein Beispiel:
Angenommen, es gibt ein Loginfeld, über das sich Benutzer einloggen können. Dazu muss ein Benutzername und ein Passwort eingegeben werden. Da ich davon ausgehe, dass die Daten über ein Formular übergeben werden, stehen sie im Array [var]$_POST[var] zur Verfügung. Eine entsprechende Datenbankabfrage könnte dann so aussehen:
PHP:
<?php
$sql = "SELECT
ID
FROM
User
WHERE
Benutzername = '".$_POST['Benutzername']."' AND
Passwort = '".$_POST['Passwort']."'
";
$result = mysql_query($sql);
?>
Wenn nun ein Angreifer einen auf dem System registrierten Benutzername kennt, kann er sich nun einloggen. Dazu gibt er für den Benutzernamen den Namen des Users ein, in dessen Account er sich einloggen will, z.B. Admin. Als Passwort verwendet er dann folgende Zeichenkette: ' OR '1' = '1
Das würde nun den folgenden Query erzeugen:
PHP:
<?php
$sql = "SELECT
ID
FROM
User
WHERE
Benutzername = 'Admin' AND
Passwort = '' OR '1' = '1'
";
$result = mysql_query($sql);
?>
Die Datenbank wird nun nach dem Benutzer Admin durchsucht, dessen Passwort eine leere Zeichenkette ist. Dadurch würde kein Benutzer gefunden werden, indem aber noch ein
OR '1' = '1
angehangen wird, ist das Passwort egal, da die zweite Bedingung des ORs immer erfüllt ist.
Weitere SQL-Befehle anhängen
Es ist jedoch nicht nur möglich, sich in einen anderen Account einzuhacken, sondern man kann auch bedeutet mehr Schaden anrichten, indem man einen zweiten Befehl unterschiebt.
Als Benutzernamen wähle ich wieder Admin, was in diesem Fall jedoch egal ist und für das Passwort benutze ich ; DELETE * FROM User.
Daraus ergibt sich folgender Query:
PHP:
<?php
$sql = "SELECT
ID
FROM
User
WHERE
Benutzername = 'Admin' AND
Passwort = ''; DELETE * FROM User
";
$result = mysql_query($sql);
?>
Sofern die Datenbank es zulässt, werden nun alle Datensätze in der Tabelle User gelöscht. Das ist so was wie der Super GAU bei einer Datenbanktabelle.
Auftreten
SQL Injection tritt an jeder Stelle auf, an der ein User Eingaben vornehmen kann, die einen MySQL-Query auslösen. Das sind z.B. Logindaten, Erstellen von Gästebucheinträgen, Erstellen von Forenbeiträgen, Suchanfragen, Anzeigen von Benutzerprofilen (durch die in der URL übergebene ID), etc...
mysql_real_escape_string und das magic_quotes_gpc Problem
Die Injection 'lebt' von den MySQL-Steuerzeichen wie Single Quotes ( ' ), Double Quotes ( " ) und Backslahes ( \ ). Diese Zeichen müssen demnach maskiert werden, so dass sie zwar als 'normale' Zeichen gewertet werden, aber ihre Funktionalität als Steuerzeichen verlieren. Eigentlich sorgt PHP in den meisten Fällen selbständig dafür, dass diese Zeichen maskiert werden. Dazu kann die Einstellung magic_quotes_gpc in der php.ini auf 'on' gestellt werden. Das ist zwar häufig der Fall, hat aber den Nachteil, das es auf jedes '," und \ angewendet wird, selbst wenn sie bereits escaped wurden. Dadurch können x-fach-Escapungen (ich denke mal das Wort gibt es nicht.. aber es lebe der Neologismus ) entstehen. Aus diesem Grunde ziehe ich es vor, [v]magic_quotes_gpc[/v] zu deaktivieren. Sollte das nicht möglich sein, weil ihr keinen Zugriff auf die php.ini habt, könnt ihr das Ganze 'manuell' außer Kraft setzen. Dazu verwendet man einfach diese Funktion, die ich von #PHP/QuakeNet übernommen habe:
PHP:
<?php
// stripslahes für ein mehrdimensionales Array
function array_stripslashes(&$variable)
{
// Prüft, ob die Variable ein String ist
if (is_string($variable))
// Fall ja, wird stripslashes auf diesen String angewandt
$variable = stripslashes($variable);
// Falls nicht, wird geprüft ob sie ein Array ist
else {
// Ist das der Fall, ruft sich die Funktion rekursiv selbst wieder auf
if (is_array($variable)) {
foreach($variable AS $key => $value)
array_stripslashes($variable[$key]);
}
}
}
?>
und ruft sie am Anfang des Scriptes folgendermaßen auf:
PHP:
<?php
if (get_magic_quotes_gpc()) {
array_stripslashes($_POST);
// optional auch auf $_GET und $_COOKIE anwenden
array_stripslashes($_GET);
array_stripslashes($_COOKIE);
}
?>
Nachdem magic_quotes_gpc nun von uns außer Kraft gesetzt wurde, sichern wir den Query selbst. Dazu verwenden wir die Funktion addslashes(), oder optimalerweise die Funktion mysql_real_escape_string(), die genau zu diesem Zweck geschaffen wurde. Der korrekte Quellcode eines MySQL-Querys sieht dann so aus:
PHP:
<?php
$sql = "SELECT
ID
FROM
User
WHERE
Benutzername = '".mysql_real_escape_string($_POST['Benutzername'])."' AND
Passwort = '".mysql_real_escape_string($_POST['Passwort'])."'
";
$result = mysql_query($sql);
?>
Bewerten