De meest betrouwbare manier is om altijd geparameteriseerde query's of voorbereide instructies (prepared statements) te gebruiken, en NIET om query's te vormen door simpelweg strings met gebruikerswaarden te concatenëren.
Voor complexere scenario's (dynamische SQL binnen procedures) — gebruik speciale escaperingsmechanismen en whitelisting (strikte filtering) van parameters.
cursor.execute('SELECT * FROM users WHERE login = %s', [login])
EXECUTE format('SELECT * FROM %I WHERE id = $1', tablename) USING id;
Hier vervangt %I alleen tabel- of kolomnamen op een veilige manier.
Is de volgende benadering veilig bij het invoegen van een getal in een string?
EXECUTE 'SELECT * FROM users WHERE id = ' || user_input;
NEE! Zelfs als je een getal verwacht, kan een aanvaller code invoeren:
1; DROP TABLE users; — de query wordt uitgevoerd. Gebruik daarom altijd placeholders en een expliciete typecontrole van invoerparameters.
Verhaal 1
Een zoekformulier voor medewerkers genereerde WHERE-voorwaarden via stringconcatenatie aan de applicatiezijde. Een aanvaller voerde in: ' OR 1=1 --, wat de gegevens van alle medewerkers onthulde. Later werd via een soortgelijke benadering een gegevenssectie verwijderd. Conclusie: concatenatie van belangrijke parameters is altijd een risico.
Verhaal 2
In de administratieve interface voor het kiezen van een rapport werd de tabelnaam uit een gebruikersveld gehaald en in de SQL-query ingevoegd. De gebruiker kon een ongeldig naam invoeren en toegang krijgen tot systeemtabelen. Vervolgens werden alleen hardcoded namen toegestaan (whitelisting).
Verhaal 3
In een e-commerce project, bij dynamische sortering, gaven gebruikers de naam van het veld door via een GET-parameter. Een hacker voegde price; DELETE FROM orders; -- in, wat leidde tot het verlies van alle bestellingen. Filtering van toegestane kolomnamen en het gebruik van geparameteriseerde query's loste het probleem op.