Reproduziere eine SQL-Injection, neutralisiere sie mit Prepared Statements und wende das Prinzip der geringsten Rechte an.
Diese Lektion in Kodokon öffnenEine SQL-Injection entsteht in dem Moment, in dem nicht vertrauenswürdige Daten in den Text einer Abfrage eingefügt werden. Der Angreifer liefert einen Wert, der die Zeichenkette schließt und die Logik entführt. Reproduzieren wir den Angriff auf eine users-Tabelle: Die Eingabe ada' OR '1'='1 direkt zu verketten, verwandelt einen präzisen Filter in eine stets wahre Bedingung.
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
is_admin INTEGER NOT NULL DEFAULT 0
);
INSERT INTO users (id, name, is_admin)
VALUES (1, 'ada', 0), (2, 'root', 1);
-- Dangerous concatenation (NEVER do this)
-- input = ada' OR '1'='1
SELECT * FROM users
WHERE name = 'ada' OR '1'='1';Die Payload funktioniert, weil das Anführungszeichen das Literal 'ada' vorzeitig schließt, dann fügt OR '1'='1' eine allgemeingültige Bedingung hinzu. Eine Variante hängt -- an, um den Rest der ursprünglichen Abfrage auszukommentieren. Die Lehre: Solange die Daten und der Code sich dieselbe Zeichenkette teilen, ist kein manuelles Escaping wirklich zuverlässig.
-- Positional placeholder
SELECT * FROM users WHERE name = ?;
-- Named placeholder
SELECT * FROM users WHERE name = :name;Das Gegenmittel ist das Prepared Statement: Der Treiber kompiliert zuerst die Struktur der Abfrage und bindet dann die Werte separat. Die gebundenen Daten werden nie als SQL geparst, nur verglichen. Als Bonus ist die kompilierte Struktur wiederverwendbar: Mehrere Werte nacheinander zu binden, vermeidet, den Plan bei jedem Aufruf neu zu kompilieren.
-- The bound value stays data, not SQL
SELECT * FROM users
WHERE name = :name;
-- :name = ada' OR '1'='1
-- -> 0 rows: no user
-- is literally named that' OR '1'='1 gelingt bei der Injection, weil sie...?-Parameter binden?:name