O'Reilly logo

PHP-Sicherheit: PHP/MySQL-Webanwendungen sicher programmieren by Stefan Esser, Christopher Kunz

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

1395.5 Schutz vor SQL-Injection
(id=1&&conv(substring(passwd,1,1),16,10) &1) // 1. Stelle
(id=1&&conv(substring(passwd,1,1),16,10) &2) // 2. Stelle
(id=1&&conv(substring(passwd,1,1),16,10) &4) // 3. Stelle
(id=1&&conv(substring(passwd,1,1),16,10) &8) // 4. Stelle
Ist das Bit an der entsprechenden Stelle gesetzt, wird eine Zahl
ungleich 0 zurückgegeben. So kann man auch wieder anhand der Sor-
tierung überprüfen, ob das Bit an der entsprechenden Stelle gesetzt ist.
In unserem nächsten Beispiel liegt ein Passwort-Hash vor, der an der
ersten Stelle den Buchstaben »
b« hat.
Beispiel für einen Angriff
mit der
CONV()
-Funktion
conv(substr(passwd,1,1),16,10) &1// ergibt 1 = 1
conv(substr(passwd,1,1),16,10) &2// ergibt 2 = 1
conv(substr(passwd,1,1),16,10) &4// ergibt 0 = 0
conv(substr(passwd,1,1),16,10) &8// ergibt 8 = 1
Das bedeutet für uns eine Binärzahl von 1011. Hier muss man die Stel-
len von hinten nach vorne betrachten.
Um einen Passwort-Hash auf diese Art zu erraten, benötigt man
nun noch 4*32 (128) Requests, muss jedoch die Namen der Daten-
bankfelder kennen. Bei Software, die nicht öffentlich verfügbar ist, ist
dieses Wissen schwer zu erlangen.
5.5 Schutz vor SQL-Injection
Um sich vor einer SQL-Injection zu schützen, bietet PHP einige Funk-
tionen an. In den folgenden Abschnitten werden Ihnen Strategien
erklärt, wie Sie sich vor einer SQL-Injection schützen können.
5.5.1 Sonderzeichen maskieren
Wie wir gesehen haben, werden mit mysql_real_escape_string() die
Sonderzeichen maskiert. So haben diese keinen Einfluss auf das SQL-
Statement mehr. Diese werden aber nicht in der Datenbank gespei-
chert.
magic_quotes_gpc, mysql_real_escape_String() oder addslahses()?
Ist in der Konfigurationsdatei php.ini die Einstellung magic_quotes_gpc
auf on gesetzt, werden alle Sonderzeichen, die aus GET, POST oder
Cookie-Variablen kommen, ebenfalls mit einem Backslash maskiert.
Bei
magic_quotes_gpc wird aber der Backslash in den zu behandelnden
String eingefügt und so mit in der Datenbank gespeichert.
Eine weitere Möglichkeit, Sonderzeichen zu maskieren, ist die
PHP-Funktion
addslashes(). Hier werden ebenfalls die Sonderzeichen
mit in der Datenbank gespeichert.
5 SQL-Injection 140
Für das Entfernen der Backslashes beim Auslesen gibt es die PHP-
Funktion
stripslashes(). Diese entfernt alle Backslashes aus dem String.
An eine Sonderzeichenbehandlung sollte auf jeden Fall gedacht
werden. Je nachdem, wie Ihre Produktivumgebung aussieht, kann man
mysql_real_escape_string() oder addshlashes() benutzen. Vorteil bei
diesen beiden Funktionen: Man hat volle Kontrolle über die eingefüg-
ten Backslashes. Auf jeden Fall muss man, bevor man
addslashes()
verwendet, überprüfen, ob magic_quotes_gpc an- oder ausgeschaltet ist.
Falls es auf
on steht, ist eine weitere Behandlung mit addslashes() nicht
nötig.
5.5.2 Ist Schlüsselwort-Filterung ein wirksamer Schutz?
Diese Frage kann man nicht mit hundertprozentiger Sicherheit beant-
worten. Eine Filterung auf Schlüsselwörter birgt immer Gefahren in
sich. Man sollte auf jeden Fall auf eine eventuelle Groß- und Klein-
schreibung achten. Speziell die Schlüsselwörter
AND, OR, SELECT, UNION
und ORDER sollten gefiltert werden. Ob nach oder vor diesen Schlüssel-
wörtern ein Leerzeichen kommt, darf bei einer Filterung nicht relevant
sein, denn Sie können nach einem dieser Schlüsselwörter ein Kommen-
tarzeichen einfügen.
[…] ORDER/**/ BY
[…] SELECT/**/ name […]
In diesen Beispielen ist eine Prüfung auf Schlüsselwort + Leerzeichen
sinnlos. Außerdem kann es durchaus Feldinhalte geben, in denen diese
Schlüsselwörter wirklich enthalten sind. Zum Beispiel die Bielefelder
Firma »UNION Knopf« oder die Firma »Papier Union«.
5.5.3 Parameter Binding/Prepared Statements
Gebundene Parameter sind auch bekannt als »Prepared Statements«.
Diese erzeugen mithilfe eines Query-Templates ein SQL-Statement,
das dann auf dem MySQL-Server gespeichert wird. In PHP funktio-
niert dies mit der neuen MySQL-Extension »mysqli«.
mysqli_ prepare() Hier wird ein SQL-Statement mit der Funktion mysqli_prepare()
vorbereitet. Danach kann man mit mysqli_stmt_bind_param() einen
oder mehrere Parameter daran binden.
mysqli_stmt_bind_
param()
Das vorbereitete SQL-Statement wird dann an den MySQL-Server
gesendet und dort ausgeführt. Dabei wird automatisch ein
mysql_real_escape_string() auf alle Parameter durchgeführt. Das
SQL-Statement wird dann in einem speziellen Speicherbereich auf dem
MySQL-Server gespeichert, und für die spätere Verwendung erhalten
1415.5 Schutz vor SQL-Injection
Sie ein Handle auf dieses Prepared Statement. Für spätere Verwendun-
gen müssen dann nur noch die neuen Parameter daran gebunden wer-
den. Ein erneutes Senden des Templates ist nicht mehr notwendig.
Es werden nur noch Daten
an den Server geschickt
.
Das bedeutet für SQL-Statements, die nur wenige Daten übertra-
gen müssen: Es werden nur die Daten erneut zum Server geschickt,
nicht mehr das komplette SQL-Statement.
Ein Beispiel:
INSERT INTO City (ID, Name) VALUES (NULL, 'Frankfurt');
Bei erneutem Senden werden nur das Feld »Name« und wenige Steuer-
informationen, wie die ID des Prepared Statements, übertragen.
Ein solches Template sieht wie folgt aus:
INSERT INTO City (ID, Name) VALUES (?, ?);
Die Fragezeichen »?« sind Platzhalter für die Daten. Hier ein komple-
xeres Beispiel:
<?php
// Anmelden am MySQL-Server
$res = mysqli_connect('localhost', 'user', 'password', 'testDB');
/* Verbindung überprüfen*/
if (mysqli_connect_errno()) {
printf("Connect fehlgeschlagen: %s\n", mysqli_connect_error());
exit();
}
// Das Statement vorbereiten
$stmt = mysqli_prepare($res,"INSERT INTO users VALUES (?, ?, ?,
?)");
// Parameter daran binden
mysqli_bind_param($stmt, 'sssi', $name, $vorname, $email, $alter);
$name = 'Prochaska';
$vorname = 'Peter';
$email = 'info@peter-prochaska.de';
$alter = 32;
/* Prepared Statement ausführen*/
mysqli_execute($stmt);
/* Das Statement schließen */
mysqli_stmt_close($stmt);
/* Verbindung schließen*/
mysqli_close();
?>
Die Funktion mysqli_bind_param() hat als zweiten Parameter einen
String »sssi«. Dieser String ist eine Formatangabe für den Datentyp.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required