PHP – Kanntest du schon? – SQL Injections

SQL Injections ist ein Thema seit jeher. Die Gefahr ist, dass man über Eingabefelder die SQL-Abfrage so manipulieren kann, um Zugriff auf andere Daten zu erhalten. Das ist einfacher als man denkt. Folgende Beispiel PHP Datei:

Als Beispieldatenbank nehme ich die Datenbank phplogin aus dem Artikel des PHP Login Projekt welche eine Tabelle account erhält. Hier stehen sehr sensible Informationen drin und wir können uns über das simple Query alle Account-Daten aus der Tabelle ausgeben lassen. Wie? Ganz einfach:

Normalerweise würden wir in das Input-Feld nur unsere E-Mail Adresse eintragen, ein Bösewicht (auch Cracker – fälschlicherweise Hacker) genannt könnte aber statt seine E-Mail die obige Zeile eingeben. Eigentlich sollte nur jeder User seine Daten als Ausgabe erhalten, doch folgende Ausgabe erhalten wir:

Wir erhalten alle Daten aus der Tabelle und zwar nicht nur für unseren Benutzer, denn durch die Eingabe hat sich das SQL-Statement von

in folgendes geändert:

Entweder ist die Mail leer, oder 1=1. 1=1 ist eine Bedingung, man könnte sie auch true nennen, die immer zutrifft und damit die Bedingung sofort erfüllt und das Statement ausführt.

Wie verhindert man SQL Injections?

Das Stichwort, bzw. die Stichwörter hier lauten: Prepared Statements. Wie der Name schon erahnen lässt gibt man hier die Daten nicht direkt als gesamtes SQL-Statement an den Datenbank Server. Vielmehr lässt man den Datenbankserver das Statement vorbereitet. Das tun wir, indem wir ihm folgendes SQL-Statement “preparen” lassen:

Er weiß jetzt was er machen soll, nämlich einen SELECT * aus der Tabelle account und als Bedingung wird eine email kommen. Der Server kann Vorbereitungen treffen hat aber noch keine konkreten Daten zum Ausführen dieses Befehls. Erst im zweiten Schritt lässt man den Datenbankserver dieses Statement ausführen und gibt ihm zeitgleich als Parameter die Daten mit, Ausschnitt:

Weil man beim PDO-Connector besser mit Prepared Statements arbeiten kann und dieser im Gegensatz zum MySQLi-Connector Named Parameters unterstützt und auch aus weiteren Gründen, habe ich in diesem Beispiel zur Prävention von SQL-Injection vom MySQLIi-Connector zum PDO-Connector gewechselt.

Der vollständige Code hier:

Geben wir nun unsere E-Mail Adresse ein, erhalten wir nur unsere Daten. Verwenden wir wieder den Teil für die SQL-Injection (siehe unten), erhalten wir eine leere Seite (weiß), weil intern ein Fehler geworfen wird der bei mir zumindest nicht direkt angezeigt wird.

MySQL Remote Access einrichten

Damit man außerhalb auf eine MySQL-Datenbank zugreifen kann und das ohne phpMyAdmin kann man Software für Windows, Mac oder Linux verwenden. Jeder Datenbankhersteller bietet sein eigenes Tool an, so ist dies bei MySQL zum Beispiel über die MySQL Workbench möglich. Eine Drittanbietersoftware wäre Navicat in diversen Versionen für unterschiedliche Datenbank oder dem “Premium”, die alle unter einem Dach vereint. Navicat ist allerdings nicht kostenlos erhältlich.

Diese Anleitung bezieht sich auf eine MySQL-Datenbank auf einem Debian Linux.

Schritt 1: Privilege setzen

Die Privilegien setzen. Dazu müssen wir einen SQL-Befehl via Konsole oder phpMyAdmin absetzen. Dieser lautet:

Man sollte dies allerdings nicht auf dem root-User anwenden.

  • database.* bedeutet auf alle Tabellen in der Datenbank database. Ein *.* ist ebenfalls möglich.
  • user ist der Benutzer auf den diese Rechte angewendet werden.
  • % ist der Bereich, die Domain, IP. %.domain.com oder 192.168.0.% sind möglich, % bedeutet, egal woher.
  • newpassword ist das Passwort des Benutzers user.

Schritt 2: IP-Binding anpassen

Eine weitere Schutzmaßnahme kommt out-of-the-box daher. In der Datei /etc/mysql/my.cnf gibt es unter der Sektion [mysqld] den Eintrag:

Nun gibt es zwei Möglichkeiten:

  1. Diese Zeile auskommentieren mit einer # als erstes Zeichen, dass ermöglicht allen IP-Adressen den Zugriff von außerhalb.
  2. Einfach eine weitere IP-Adresse “binden”. Habt ihr keine statische IP in eurem Netzwerk ändert sich diese aber z.B. beim Neustart. Dafür kommt wirklich nur ihr auf die Datenbank.

Schritt 3: Neustart

Ggf. muss der mysql-Dienst neugestartet werden, dies passiert unter Linux mit dem Befehl:

Fertig!