🛡️SQL-Injection und Prepared Statements
Werden Benutzereingaben direkt in SQL-Text eingesetzt, kann ein Angreifer die Abfrage umschreiben. Die Demo läuft vollständig im Browser gegen eine erfundene Tabelle – die Passwörter stehen nur zur Veranschaulichung im Klartext.
Richtige Daten: genau eine Zeile – in beiden Varianten.
❌ Unsicher: Text zusammenkleben
sql = "SELECT … WHERE benutzer = '" + benutzer + "' AND passwort = '" + passwort + "';"
SELECT id, benutzer, rolle FROM konten WHERE benutzer = 'anna' AND passwort = 'beispiel-passwort-anna';
Rot: was aus der Eingabe stammt. Die Datenbank kann nicht unterscheiden, was Daten und was Befehl ist.
✅ Sicher: Prepared Statement
stmt = db.prepare("SELECT id, benutzer, rolle FROM konten WHERE benutzer = ? AND passwort = ?;")
stmt.bind([benutzer, passwort])SELECT id, benutzer, rolle FROM konten WHERE benutzer = ? AND passwort = ?;
? ← "anna"
? ← "beispiel-passwort-anna"
? ← "beispiel-passwort-anna"
Der SQL-Text steht fest, bevor die Werte ankommen. Die Werte werden nur noch als Daten verglichen – ein Anführungszeichen ist dann einfach ein Zeichen.
🧰Prepared Statements in verschiedenen Sprachen
Platzhalter heißen je nach Treiber ?, :name oder $1 – das Prinzip ist immer gleich.
Python (sqlite3)
cur.execute(
"SELECT id FROM konten WHERE benutzer = ? AND passwort_hash = ?",
(benutzer, passwort_hash),
)Java (JDBC)
PreparedStatement ps = con.prepareStatement(
"SELECT id FROM konten WHERE benutzer = ? AND passwort_hash = ?");
ps.setString(1, benutzer);
ps.setString(2, passwortHash);
ResultSet rs = ps.executeQuery();PHP (PDO)
$st = $pdo->prepare(
'SELECT id FROM konten WHERE benutzer = :b AND passwort_hash = :h');
$st->execute(['b' => $benutzer, 'h' => $hash]);Node.js (pg)
await client.query( "SELECT id FROM konten WHERE benutzer = $1 AND passwort_hash = $2", [benutzer, passwortHash], );
📌Weitere Schutzschichten
⚠️ Platzhalter gibt es nur für Werte
Tabellen- und Spaltennamen (z. B. eine wählbare Sortierspalte) lassen sich nicht binden. Dann gegen eine feste Liste erlaubter Namen prüfen (Allowlist).
💡 Minimale Rechte
Die Anwendung verbindet sich mit einem Benutzer, der nur darf, was sie braucht (GRANT SELECT, INSERT … auf bestimmte Tabellen) – kein DROP, kein Zugriff auf andere Schemata.
✅ Passwörter nie speichern
Gespeichert wird ein langsamer, gesalzener Hash (Argon2id, bcrypt, scrypt). Der Vergleich passiert in der Anwendung, nicht per SQL-Gleichheit auf dem Klartext.