L'injection SQL n'est pas morte
Malgré 25 ans de sensibilisation, l'injection SQL reste dans le top 3 des vulnérabilités exploitées. Les ORM ont réduit la surface d'attaque mais n'ont pas éliminé le problème. Chaque fois qu'un développeur écrit une requête brute, concatène un paramètre utilisateur dans du SQL, ou utilise un ORM en mode unsafe, le risque revient.
Comment ça fonctionne
L'attaquant insère du SQL dans un champ qui sera intégré à une requête côté serveur. Si la valeur n'est pas paramétrée, le moteur SQL l'interprète comme du code.
Exemple basique : le formulaire de login exécute SELECT * FROM users WHERE email = '[input]' AND password = '[input]'. L'attaquant saisit admin'-- comme email. La requête devient SELECT * FROM users WHERE email = 'admin'--' AND password = ''. Le commentaire SQL -- ignore la vérification du mot de passe.
Les variantes
Union-based
L'attaquant utilise UNION SELECT pour extraire des données d'autres tables. Si la requête originale retourne 3 colonnes, l'attaquant injecte ' UNION SELECT username, password, email FROM users-- pour récupérer les identifiants de tous les utilisateurs.
Blind (booléen)
Quand l'application ne retourne pas les résultats directement, l'attaquant pose des questions oui/non. ' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE id=1)='a'-- teste si le premier caractère du mot de passe est a. En automatisant, on extrait la base caractère par caractère.
Time-based
Même principe que le blind, mais basé sur le temps de réponse. ' AND IF(1=1, SLEEP(5), 0)-- provoque un délai de 5 secondes si la condition est vraie. Plus lent mais fonctionne même quand les réponses sont identiques.
Second-order
L'injection n'est pas exploitée immédiatement. La valeur malveillante est stockée (par exemple dans un profil utilisateur), puis utilisée plus tard dans une autre requête non paramétrée. Plus difficile à détecter car l'entrée et la sortie sont séparées.
Ce que les ORM ne protègent pas
DB::raw() dans Laravel : toute expression brute réintroduit le risque.extra() dans Django : injections dans les clauses WHERE additionnellesORDER BY dynamiques : souvent construites par concaténation même dans les ORMDéfenses modernes
? ou ``). Jamais de concaténation.DROP, pas de FILE, pas d'accès aux tables système.Ce que nous trouvons en audit
Chez CleanIssue, nous trouvons des injections SQL dans environ 15% des applications auditées. La majorité concerne des requêtes de recherche avec tri dynamique ou des exports CSV avec filtres personnalisés. Parlez-nous de votre revue externe pour vérifier vos endpoints les plus exposés.
Articles liés
Trois analyses proches pour continuer la lecture sur la meme surface de risque.
XSS expliqué : reflected, stored, DOM-based, comment se protéger
Les trois types de Cross-Site Scripting décortiqués avec des exemples concrets, les vecteurs d'attaque courants et les défenses à implémenter.
PostgreSQL et CVE-2018-1058 : pourquoi le search_path reste un risque sous-estime
CVE-2018-1058 n etait pas une injection SQL classique mais un probleme de search_path et de schemas. Voici pourquoi cette faille PostgreSQL reste pedagogique en 2026.
Python et Django : pourquoi CVE-2025-64459 doit etre pris au serieux
CVE-2025-64459 a rappele que meme un ORM reputé sur peut exposer une injection SQL dans certaines conditions. Voici pourquoi cette faille Django doit etre prise au serieux.
Sources
Analyse éditoriale fondée sur la documentation officielle des éditeurs, projets et autorités concernées.
Services associés
Si ce sujet reflète un risque concret sur votre stack, voici les audits CleanIssue les plus pertinents.