PHP.de Wissenssammlung

SQL-Injection

Ursprung

SQL-Injections fallen in den Bereich der Kontextwechsel-Probleme.

SQL-Queries werden in PHP als normaler String zusammengebaut. Dynamisch hinzugefügte Werte (etwa eine Benutzereingabe in $_POST['name']) können dabei die vorgesehene Logik der Query verändern, wenn sie für den Kontext syntaktisch relevante Zeichen (etwa die Anführungszeichen " und ') enthalten.

$_POST['name'] = "Max' OR 1 --";
$query = "DELETE FROM nutzer WHERE name = '" . $_POST['name'] . "'";
// Resultierender String:
// DELETE FROM nutzer WHERE name = 'Max' OR 1 --'

In diesem Beispiel gelingt es der Eingabe in $_POST['name'], durch ein geschickt platziertes Anführungszeichen den Kontext „String in einer SQL-Query“ zu verlassen und in den Kontext „SQL-Query“ darüber auszubrechen. Dort wird die Bedingung, welche Einträge aus nutzer gelöscht werden sollen, um den Teil OR 1 erweitert und die Abfrage sofort danach mit einem Kommentar (eingeleitet durch --) beendet. Das führt dazu, dass die Gesamtbedingung für jeden Datensatz in dieser Tabelle erfüllt ist. Durch die fertige Abfrage werden somit alle Datensätze in der Tabelle gelöscht.

Wie bei allen Kontextwechseln muss derlei unerwünschten Effekten kein gezielter Angriffsversuch vorausgehen. Im Beispiel würde bereits die Eingabe eines Namens wie O'Brian die Query syntaktisch ungültig werden und fehlschlagen lassen.

Gegenmaßnahmen

Zur Vermeidung von SQL-Injections dienen Funktionen, die die syntaktisch relevanten Zeichen, die in Eingaben enthalten sein können, durch Escaping so anpassen, dass sie nicht mehr zu einem Kontextwechsel führen. Aus " wird so beispielsweise \". Das verdeutlicht dem Datenbanksystem, dass hier kein Stringbegrenzer gemeint ist (syntaktische Funktion), sondern lediglich das konkrete Zeichen " (reiner Inhalt).

Anwendung

Für jede Datenbankschnittstelle existiert mindestens eine spezielle Funktion oder Methode, die dieses Escaping durchführen kann. Es muss diese zur Schnittstelle gehörende Funktion genutzt werden. Eine allgemeine Funktion wie addslashes ist nicht ausreichend. Eine Auswahl dieser Funktionen für einige Schnittstellen:

Die Anwendung dieser Funktionen ist quasi immer gleich und nicht sonderlich kompliziert: Bevor ein Wert in den Query-String eingefügt wird, muss er die passende Escape-Funktion durchlaufen.

$query = "
    DELETE FROM nutzer
    WHERE name = '" . mysqli_real_escape_string($link, $_POST['name']) . "'
";

Sicher ist sicher

Es ist zu empfehlen, jeden variablen Wert, der in Query-Strings eingefügt wird, durch die passende Escape-Funktion zu schicken. Also auch dann, wenn der Wert je nach Logik der Anwendung nur beispielsweise aus [0-9A-Za-z] bestehen kann. Diese Beschränkung könnte sich ändern oder sie könnte durch einen Bug umgangen werden. Auch sollte kein Entwickler kognitive Leistung dafür aufbringen müssen, darüber nachzudenken, warum an einer Stelle eine Escape-Funktion fehlt. Schließlich wäre es denkbar, dass sie versehentlich vergessen wurde.

Prepared-Statements

Viele Datenbankschnittstellen unterstützen zusätzlich das Konzept der Prepared Statements, das ebenfalls SQL-Injections verhindert.

Dieser Beitrag wird zur Zeit diskutiert und wurde zuletzt von hausl verändert.

Beiträge die zur Diskussion gestellt werden, enthalten mitunter Informationen bei denen wir uns noch bezüglich der finalen Darstellung absprechen müssen. Gedulde dich etwas, wir stellen diesen Beitrag fertig, sobald die Diskussion beendet ist.

An diesem Beitrag waren bisher beteiligt: nikosch, mermshaus, hausl