Der sicherste Weg ist immer die Verwendung von parametrisierten Abfragen oder vorbereiteten Anweisungen (prepared statements) statt SQL-Abfragen durch einfache String-Konkatenation mit Benutzereingaben zu erstellen.
Für komplexere Szenarien (dynamisches SQL innerhalb von Prozeduren) sollten spezielle Mechanismen zur Escaping und Whitelisting (strikte Filterung) von Parametern angewendet werden.
cursor.execute('SELECT * FROM users WHERE login = %s', [login])
EXECUTE format('SELECT * FROM %I WHERE id = $1', tablename) USING id;
Hier ersetzt %I sicher nur die Namen von Tabellen/Spalten.
Ist der folgende Ansatz sicher, wenn eine Zahl in einen String eingefügt wird?
EXECUTE 'SELECT * FROM users WHERE id = ' || user_input;
NEIN! Selbst wenn Sie eine Zahl erwarten, kann ein Angreifer Code übergeben:
1; DROP TABLE users; — die Abfrage wird ausgeführt. Daher sollten immer Platzhalter und eine explizite Typüberprüfung der Eingangsparameter verwendet werden.
Geschichte 1
Das Suchformular für Mitarbeiter baute WHERE-Bedingungen durch String-Konkatenation auf der Anwendungsseite. Ein Angreifer gab ein: ' OR 1=1 -- ein, was die Daten aller Mitarbeiter zurückgab. Später wurde durch einen ähnlichen Ansatz ein Datensatz gelöscht. Fazit: Die Konkatenation von bedeutenden Parametern ist immer ein Risiko.
Geschichte 2
Im administrativen Interface zur Auswahl eines Berichts wurde der Tabellenname aus einem Benutzerfeld gezogen und in die SQL-Abfrage eingefügt. Der Benutzer konnte einen ungültigen Namen einfügen und auf Systemtabellen zugreifen. Danach wurden nur fest definierte Namen (Whitelisting) erlaubt.
Geschichte 3
In einem E-Commerce-Projekt übermittelten Benutzer den Namen des Feldes über GET-Parameter zur dynamischen Sortierung. Ein Hacker fügte price; DELETE FROM orders; -- hinzu, was zum Verlust aller Bestellungen führte. Die Filterung zulässiger Spaltennamen und die Verwendung von parametrisierten Abfragen lösten das Problem.