Datenbanksicherheit mit PHP

Beim Arbeiten mit Datenbanken muss man sich gegen verschiedene Angriffsmöglichkeiten wappnen. Zu den verbreitetsten zählen SQL-Injections (dt. SQL-Einschleusungen). Hierbei versucht der Angreifer SQL-Befehle als Parameter, die in die MySQL-Abfrage einfließen, zu übergeben.

SQL-Injection Beispiel

Um sich gegen Angriffe zu wehren, muss man die Methode verstehen. In diesem Beispiel geht es darum, dass völlig andere Befehle an das Ende eines über die GET-Methode übergebenen Parameters gehängt wird.

<?php
  $user_id = $_GET['id'];
  $abfrage = "SELECT namen FROM user WHERE id = ".$user_id;
  $ergebnis = mysql_query($abfrage);
  // ...
?>

Nehmen wir an, der User hat die id = 3. Die URL für diesen Code wäre dann vermutlich dateiname.php?id=3. Ein bösartiger Angreifer kann nun, da der Inhalt der Variable $_GET['id'] nicht auf seine Plausiblität geprüft wird, schadhaften Code anhängen:

dateiname.php?id=3';+DELETE+FROM+user+WHERE+id+>+'0';--

Der SQL-Befehl, der ausgeführt wird, sieht also so aus:

SELECT namen FROM user WHERE id = '3'; DELETE FROM user WHERE id > '0'--'

In diesem Fall würden zusätzlich zum Auslesen des Namens des User mit der id=3 alle Datensätze, deren id größer als 0 ist, in der „user“-Tabelle gelöscht. Die beiden - - am Ende sind Kommentare in der SQL Sprache, vergleichbar mit doppelten Schrägstrichen in PHP oder C. Es werden alle nachfolgenden Zeichen, in diesem Fall der Rest der ursprünglichen Abfrage, also ein ' ignoriert.

Gegenmaßnamen bei Integer-Variablen

Bei Integer-Variablen, also Variablen, die nur Zahlen enthalten sollten, wie in dem oberen Beispiel, ist die Abwehr recht einfach: Man muss die übergebene Variable in einen Integer-Wert umwandeln:

<?php
  $user_id = (int) $_GET['id'];
  $abfrage = "SELECT namen FROM user WHERE id = ".$user_id;
  $ergebnis = mysql_query($abfrage);
  // ...
?>

Der Variable $user_id wird nun in jedem Fall der Integer-Wert des Variable $_GET['id'] zugewiesen. Das Anhängen eines funktionierenden SQL-Befehls an den Parameter wird somit unmöglich.

Gegenmaßnamen bei String-Variablen

Bei String-Variablen stellt PHP eine bequeme Funktion zu Verfügung, die alle SQL-Befehle erkennt und unschädlich macht bzw. maskiert: mysql_real_escape_string('string').

<?php
  $user_name = mysql_real_escape_string($_POST['name']);
  $abfrage = "SELECT id FROM user WHERE name = '".$user_name."'";
  $ergebnis = mysql_query($abfrage);
  // ...
?>

POST und GET im Vergleich

Sind nur GET-Variablen von dem unerwünschtem Verändern von Daten betroffen? Auf den ersten Blick kann es so aussehen, da man bei GET-Variablen nur die Adresszeile des Browsers verändern muss, doch auch POST-Variablen kann man mit den entsprechenden Tools (z.B. dem Firefox Addon Tamper Data) verändern. Auch Cookies sind vom User veränderbar.

In diesem Sinne:
ALL INCOMING DATA IS EVIL