Injection SQL : ne collez jamais le texte utilisateur dans une requête
Les requêtes de ce site sont tapées volontairement par vous. Dans une application, une partie du texte d'une requête vient d'un formulaire, d'une URL ou d'une API. Si ce texte est collé dans le SQL, un visiteur peut changer ce que fait l'instruction. Cette page montre l'erreur sur la base boulangerie, puis la correction. Ce n'est pas un guide pour attaquer d'autres systèmes.
La requête que vous visiez
Supposez qu'une appli cherche un client par nom de famille. Le SQL voulu est un filtre sur ce nom seulement.
SELECT first_name, last_name FROM customers WHERE last_name = 'Lopez' ORDER BY customer_id;
Résultat : Ana Lopez, une ligne.
Ce que le texte collé peut faire
Si l'appli construit l'instruction comme `WHERE last_name = '` plus ce que le visiteur a tapé plus `'`, alors taper du SQL supplémentaire dans cette chaîne change le filtre.
La requête ci-dessous est la même instruction après qu'on a tapé un nom qui ne ferme pas la quote et ajouté `OR 1 = 1`. `1 = 1` est toujours vrai, donc le WHERE ne restreint plus les lignes. Le même type de bug sur UPDATE ou DELETE sans WHERE serré peut modifier ou supprimer chaque ligne.
SELECT first_name, last_name FROM customers WHERE last_name = 'Lopez' OR 1 = 1 ORDER BY customer_id;
Résultat : Les huit clients. Le filtre sur le nom ne limite plus le résultat.
La correction : les paramètres liés
Ne collez pas le texte utilisateur dans le SQL. Envoyez l'instruction avec un placeholder et passez la valeur à part. PostgreSQL utilise `$1`, `$2`, etc. La base traite la valeur comme des données, jamais comme de la syntaxe, donc un nom qui ressemble à du SQL reste un nom.
La requête que vous écrivez est alors toujours `WHERE last_name = $1`. Les bibliothèques et ORM appellent cela une requête paramétrée ou un prepared statement. Il faut quand même s'en servir : un ORM qui concatène des chaînes a le même bug.
SELECT first_name, last_name FROM customers WHERE last_name = 'Lopez' ORDER BY customer_id;
Résultat : Ana Lopez à nouveau : la recherche avec une valeur liée, montrée ici avec un littéral parce que cet éditeur n'a pas de couche applicative.
Questions fréquentes
- Suffit-il de quotter la valeur avec des apostrophes en trop ?
- Non. On oublie un échappement, les encodages diffèrent, et les nombres ne sont pas quotés du tout. Les paramètres liés évitent toute cette classe d'erreurs.
- Un ORM veut-il dire que je peux ignorer ça ?
- Seulement si chaque requête passe par son API de paramètres. Les chaînes SQL brutes dans un ORM restent du SQL concaténé. Préférez le query builder ou `execute(sql, [value])`.
- Et UPDATE et DELETE ?
- La même règle : le WHERE doit utiliser des paramètres, jamais du texte collé. Un WHERE manquant ou cassé sur ces instructions change toute une table d'un coup.