SQL-Injection: klebe nie Benutzertext in eine Abfrage

Die Abfragen auf dieser Seite tippst du absichtlich selbst. In einer Anwendung kommt ein Teil des Texts in einer Abfrage aus einem Formular, einer URL oder einer API. Wird dieser Text in das SQL eingefügt, kann eine Besucherin ändern, was die Anweisung tut. Diese Seite zeigt den Fehler an der Bäckereidatenbank und dann die Lösung. Es ist keine Anleitung, andere Systeme anzugreifen.

Die Abfrage, die du meintest

Angenommen, eine App sucht eine Kundin nach Nachnamen. Das gemeinte SQL filtert nur auf diesen Namen.

SELECT first_name, last_name
FROM customers
WHERE last_name = 'Lopez'
ORDER BY customer_id;

Ergebnis: Ana Lopez, eine Zeile.

Was eingefügter Text anrichten kann

Wenn die App die Anweisung als `WHERE last_name = '` plus dem, was die Besucherin tippt, plus `'` baut, ändert zusätzliches SQL in dieser Zeichenkette den Filter.

Die Abfrage unten ist dieselbe Anweisung, nachdem jemand einen Nachnamen tippt, der das Anführungszeichen nicht schließt, und `OR 1 = 1` anhängt. `1 = 1` ist immer wahr, also schränkt das WHERE die Zeilen nicht mehr ein. Derselbe Fehler bei UPDATE oder DELETE ohne enges WHERE kann jede Zeile ändern oder entfernen.

SELECT first_name, last_name
FROM customers
WHERE last_name = 'Lopez' OR 1 = 1
ORDER BY customer_id;

Ergebnis: Alle acht Kunden. Der Namensfilter begrenzt das Ergebnis nicht mehr.

Die Lösung: gebundene Parameter

Füge Benutzertext nicht in SQL ein. Schicke die Anweisung mit einem Platzhalter und übergib den Wert getrennt. PostgreSQL verwendet `$1`, `$2` und so weiter. Die Datenbank behandelt den Wert als Daten, nie als Syntax, sodass ein Nachname, der wie SQL aussieht, ein Nachname bleibt.

Die Abfrage, die du schreibst, ist dann immer `WHERE last_name = $1`. Bibliotheken und ORMs nennen das eine parametrisierte Abfrage oder ein Prepared Statement. Du musst es trotzdem verwenden: ein ORM, das Zeichenketten zusammenklebt, hat denselben Fehler.

SELECT first_name, last_name
FROM customers
WHERE last_name = 'Lopez'
ORDER BY customer_id;

Ergebnis: Wieder Ana Lopez: die Suche mit einem gebundenen Wert, hier als Literal gezeigt, weil dieser Editor keine Anwendungsschicht hat.

Häufige Fragen

Reicht es, den Wert mit zusätzlichen Apostrophen zu quoten?
Nein. Leute vergessen ein Escape, Kodierungen unterscheiden sich, und Zahlen stehen gar nicht in Anführungszeichen. Gebundene Parameter umgehen diese ganze Fehlerklasse.
Heißt ein ORM, dass ich das ignorieren kann?
Nur wenn jede Abfrage über die Parameter-API läuft. Rohe SQL-Zeichenketten in einem ORM sind immer noch zusammengeklebtes SQL. Bevorzuge den Query-Builder oder `execute(sql, [value])`.
Was ist mit UPDATE und DELETE?
Dieselbe Regel: das WHERE muss Parameter verwenden, nie zusammengeklebten Text. Ein fehlendes oder kaputtes WHERE bei diesen Anweisungen ändert eine ganze Tabelle auf einmal.

Übe es