flawopen.com/SQL Injection/L’échappement suffit-il ?
Échapper les guillemets empêche-t-il SQL Injection ?
En général, non. Une fonction d’échappement dépend de la base de données, du jeu de caractères de la connexion, du mode SQL et du contexte exact des guillemets. Les requêtes paramétrées maintiennent les valeurs hors de la syntaxe SQL via l’API du pilote. Paramétrez les valeurs ; pour les identifiants dynamiques non paramétrables, choisissez une option dans une liste blanche définie par l’application.
Pourquoi l’échappement est fragile en pratique
L’échappement n’est pas un remplacement de texte indépendant du contexte. MySQL précise que mysql_real_escape_string() utilise le jeu de caractères de la connexion et que SET NAMES ne met pas à jour l’état de la bibliothèque cliente utilisé par cette fonction. Un décalage peut invalider les hypothèses sur le texte échappé. Préférez les API paramétrées ; si du code ancien doit encore échapper des valeurs, utilisez l’API du pilote avec le jeu de caractères configuré par la fonction prise en charge et gérez les erreurs.
L’échappement doit être appliqué correctement à chaque interpolation, avec le bon pilote, jeu de caractères, mode SQL et contexte de littéral. Les API paramétrées rendent la séparation valeur/donnée explicite et évitent de construire manuellement une chaîne entre guillemets.
L’échappement des guillemets ne traite que les caractères d’un littéral de chaîne donné. Il ne construit pas sûrement un nom de colonne ou de table, un mot-clé ou un sens de tri, et ne protège pas une entrée dans une expression numérique non citée. Paramétrez les valeurs et associez la structure dynamique à des options fixes de l’application.
// L’entrée utilisateur est interpolée dans la syntaxe SQL
query = f"SELECT id FROM users WHERE name = '{name}'"
cursor.execute(query)
// Le pilote lie name comme valeur de données
cursor.execute(
"SELECT id FROM users WHERE name = ?",
(name,),
)
Ce que change la liaison des paramètres
Une requête paramétrée transmet la structure SQL et les valeurs comme entrées séparées via l’API de base de données. Les pilotes peuvent utiliser des instructions préparées natives ou une autre implémentation sûre ; ne présumez pas d’un échange précis sur le protocole. La garantie est que la valeur reste une donnée et n’est pas réinterprétée comme syntaxe SQL. Avec Python DB-API, utilisez le marqueur propre au pilote et transmettez les valeurs séparément ; ne construisez pas la requête par formatage de chaîne.
Liste de contrôle technique
- ✓Liez chaque valeur utilisateur via l’API du pilote ; ne l’insérez jamais par formatage dans le SQL.
- ✓Associez les noms dynamiques de tables, colonnes et tris à une liste blanche fixe définie par l’application.
- ✓Si l’échappement historique ne peut pas encore être supprimé, utilisez l’API du pilote adaptée au contexte et vérifiez le jeu de caractères et le mode SQL de la connexion.
- ✓Testez la construction des requêtes avec des guillemets, du texte non ASCII et des identifiants invalides, sans commande destructive.
Questions fréquentes
Pour les identifiants ou fragments SQL non paramétrables, utilisez uniquement une API de citation prise en charge par le pilote avec une liste blanche fixe de l’application. Évitez l’échappement générique de valeurs arbitraires.
Elle peut aider dans le contexte documenté, mais dépend encore du moteur, des paramètres de connexion, du contexte de citation et de son usage à chaque appel. Les requêtes paramétrées restent le choix par défaut le plus sûr pour les valeurs.
Références
- OWASP — guide de prévention de SQL Injection
- CWE-89 — SQL Injection
- Manuel PHP — mysqli::real_escape_string
- API C MySQL — mysql_real_escape_string
- flawopen.com — SQL Injection (toutes les langues)