PHP, MySQL und Sicherheit
11.09.2008
Web 2.0 ist eine tolle Sache. Man kann ganze Webseiten aus dem Boden stampfen – Newssysteme anlegen oder Bildergalerien erzeugen, nur über die Besucher; ohne selbst Content generieren zu müssen.
Doch dabei gibt es auch Risiken – grundsätzlich kann man nämlich nicht darauf vertrauen dass die User immer nur Gutes im Sinn haben, oder vielleicht versuchen die Webseite zu kompromittieren.
Selbst wenn es nicht absichtlich geschieht können User durch Eingabe falscher Daten die konsistenz der Datenbank stören. Von Spambots ganz zu schweigen.
PHP ist (leider/zum Glück?) typenlos, d.h. Sie können jede Variable auch mit jeglichem Typ Daten füttern – also eine Variable die nur eine Zahl enthalten drüfte nimmt auch ohne Murren einen String auf.
Was manchmal gewollt ist verursacht an anderen Stellen Fehler: gibt ein User in ein Textfeld einen String ein, in das er eigentlich nur eine Zahl hätte eingeben dürfen und das Datenbankfeld auch so definiert wurde dass es eine Zahl fasst, dann leht der SQL-Server die Anfrage mit einem Fehler ab. Wenn es überhaupt soweit kommt. Meistens hat man dann schon einen Syntaxfehler in der Anfrage.
Es kann sogar noch schlimmer kommen: Ein User kann Daten aus der Datenbank manipulieren oder sogar löschen! Es ist natürlich unschön wenn so etwas bei einem Projekt für einen Kunden passiert.
Doch was tut man dagegen?
Nun, es ist auf jeden Fall schonmal ein Anfang zu prüfen ob die eingegebenen Werte einem bestimmten erwarteten Schema entsprechen – und diese auch in dieses Schema zu zwingen.
Zahlen konvertieren
Wo Zahlen erwartet werden dürfen also auch nur Zahlen in der SQL-Anweisung vorkommen.
Dies erreichen wir indem wir Variablen in PHP definitiv in eine Variable vom Typ Integer wandeln.
Beispiel:
$variable = (int)$_POST['texteingabe'];
Das Statement (int) direkt vor einer Eingabe veranlasst PHP dazu diese definitiv in eine Zahl umzuwandeln. Wenn darin also „1424“ stand, kommt auch wieder 1424 heraus. Sollte aber irgendein String, z.b. „Hallo“ darin gestanden haben erhalten wir eine Null (0).
Dadurch lässt sich als nächstes natürlich auch leicht prüfen ob eine korrekte Eingabe gemacht wurde.
Beispiel:
if($variable == 0) echo „Bitte füllen Sie das Formular korrekt aus“;
Lässt jemand das Textfeld leer, oder gibt einen Text, statt einer Zahl ein, wird die Fehlermeldung ausgelöst.
Strings maskieren
Texteingabe hat auch ihre Tücken. Nehmen wir mal an wir wollen zwei Text-Variablen in eine Datenbank schreiben, dann sieht das in etwa so aus:
INSERT INTO tabelle (textA, textB) VALUES ('Hallo', 'Welt');
Soweit so gut. Wenn jetzt aber ein User bei seiner Texteingabe ein ‘ – Zeichen eingetippt hat, geht das schief – SQL nimmt an der String wäre an dieser Stelle zuende (da Strings nunmal von Hochkommas oder Anführungszeichen markiert sein müssen), stolpert über ein zweites Hochkomma und ist verwirrt: es gibt einen Syntaxerror aus.
Für Fälle dieser Art verwendet man am Besten folgende Funktion:
function mask($string)
{
// Maskiert einen String für die SQL-Übergabe.
if(get_magic_quotes_gpc()) $string = stripslashes($string);
return mysql_real_escape_string($string);
}
Diese prüft zuerst ob vielleicht schon automatisch Backslashes in PHP aktiviert sind und entfernt diese ggf. – danach werden alle Sonderzeichen im übergebenen String escaped und zurückgegeben.
Achtung: Die Funktion mysql_real_escape_string() ist eine von MySQL zur Verfügung gestellte Funktion und functioniert erst nach einem erfolgreichen mysql_connect()!
Eine entsprechend bereinigter SQL-Anfrage würde also in etwa wie folgt aussehen:
$varA = mask($_POST[„variableA“]);
$varB = (int)$_POST[„variableB“];
$varC = (int) $_POST[„variableC“];
$varD = mask($_POST[„variableD“]);
$sql = „INSERT INTO tabelle (textA, zahlB, zahlC, textD) VALUES ('$varA', $varB, $varC, '$varD');“
Ein weiterer Tip:
SQL-Datenbanken und Tabellen mit der Kollation „utf8_unicode_ci“ (ganz unten in der Liste) anlegen um Formatierungsprobleme mit Umlauten und Sonderzeichen zu vermeiden.
Mit diesen Methoden wäre der Weg der Daten von der Usereingabe zur Datenbank abgesichert.
Welche Probleme und Gefahren auf dem Weg von der Datenbank zur Seite auftreten können, davon berichte ich demnächst.