cybercursus

Se protéger : requêtes préparées et bonnes pratiques

10 min · Débutant · 7 août 2026

Sommaire
  1. Revenir à la source du problème
  2. Comment fonctionne une requête préparée
  3. Ce qui complète, sans jamais remplacer

Revenir à la source du problème

Le premier chapitre de ce cours identifiait la cause commune à toutes les techniques vues depuis : une requête construite par concaténation mélange le code SQL écrit par le développeur et les données fournies par l’utilisateur, sans que le moteur de base de données puisse distinguer l’un de l’autre.

sql
-- Vulnérable : la valeur est concaténée dans le texte SQL
SELECT * FROM utilisateurs WHERE identifiant = '${identifiantFourni}'

La solution ne consiste donc pas à filtrer ou échapper des caractères dangereux au cas par cas, mais à empêcher structurellement ce mélange : c’est exactement ce que fait une requête préparée (aussi appelée requête paramétrée).

Comment fonctionne une requête préparée

Une requête préparée se déroule en deux temps bien séparés. D’abord, le texte SQL est envoyé au moteur de base de données avec des emplacements réservés (? ou :nom, selon le langage) à la place des valeurs :

sql
SELECT * FROM utilisateurs WHERE identifiant = ?

Le moteur analyse et compile cette structure une bonne fois pour toutes. Ensuite seulement, la valeur réelle est transmise séparément, pour être liée à cet emplacement :

text
requete = preparer("SELECT * FROM utilisateurs WHERE identifiant = ?")
executer(requete, [identifiantFourni])

À ce stade, identifiantFourni a beau contenir ' OR '1'='1 ou ' UNION SELECT ..., il est traité comme une seule valeur brute à comparer, jamais comme un fragment de SQL à exécuter. La structure de la requête a déjà été fixée avant même que la valeur n’entre en jeu.

Astuce

Une requête préparée neutralise indifféremment l’apostrophe qui referme une chaîne, l’injection UNION-based, et l’injection aveugle (booléenne ou temporelle) : dans les trois cas, la technique repose sur le fait que la valeur transmise est réinterprétée comme du SQL, ce qu’une requête préparée empêche par construction.

Ce qui complète, sans jamais remplacer

Les requêtes préparées restent la protection de fond contre l’injection SQL. Quelques pratiques complémentaires réduisent encore l’impact d’une éventuelle faille, sans jamais s’y substituer :

  • Principe du moindre privilège : le compte utilisé par l’application pour se connecter à la base ne doit avoir que les droits strictement nécessaires (pas de droits d’administration si l’application ne fait que lire et écrire quelques tables).
  • Validation des entrées : rejeter un identifiant qui contient des caractères impossibles pour ce champ reste une bonne pratique défensive, mais ne dispense jamais de requêtes préparées, une liste de caractères à bloquer étant presque toujours incomplète.
  • Pare-feu applicatif (WAF) : peut détecter et bloquer des charges d’injection connues, mais c’est une mesure compensatoire, pas une correction du problème à la source.
Pourquoi une requête préparée neutralise-t-elle une injection SQL, quelle que soit sa forme (apostrophe, UNION, condition booléenne) ?
Pourquoi la validation d'entrée seule (filtrer les caractères suspects) n'est-elle pas une protection suffisante contre les injections SQL ?

Pour aller plus loin

Commentaires

Recherche