SQL Injection expliquee : comment les attaquants volent les donnees des sites d'entreprise
Qu'est-ce que l'injection SQL
L'injection SQL est la plus ancienne et encore l'une des plus dangereuses vulnerabilites des applications web. Elle existe depuis la fin des annees 1990 et, malgre des decennies de sensibilisation, elle continue d'apparaitre dans les sites en production avec une frequence alarmante. Les donnees OWASP, collectees en analysant des milliers d'applications, ont trouve des failles d'injection dans 94% des applications testees. Ce chiffre devrait inquieter chaque dirigeant d'entreprise.
Le concept est simple : quand un site web prend une saisie utilisateur (un formulaire de connexion, un champ de recherche, un parametre URL) et l'insere directement dans une requete de base de donnees sans un nettoyage correct, un attaquant peut injecter ses propres commandes SQL. Au lieu de saisir un nom d'utilisateur, il saisit un fragment de code pour la base de donnees. Le serveur execute ce code comme s'il s'agissait d'une requete legitime, et l'attaquant accede a des donnees qu'il ne devrait jamais voir.
Si votre site d'entreprise conserve des donnees clients, des enregistrements de commandes, des adresses email ou toute autre information dans une base de donnees, l'injection SQL est une menace que vous devez comprendre. Pas au niveau theorique, mais en termes pratiques : comment un attaquant procede-t-il concretement, et comment l'arretez-vous ?
Comment fonctionne une requete normale de base de donnees
Avant de regarder l'attaque, comprenons ce qui se passe quand tout fonctionne correctement. Imaginez un formulaire de connexion sur votre site. Un utilisateur tape son nom d'utilisateur et son mot de passe et clique sur "Se connecter." En coulisses, votre site construit une requete de base de donnees qui ressemble a ceci :
SELECT * FROM users WHERE username = 'marco' AND password = 'monmotdepasse123'
La base de donnees recoit cette requete, cherche une ligne ou le nom d'utilisateur est "marco" et le mot de passe correspond, et retourne le resultat. Si une correspondance est trouvee, l'utilisateur est connecte. Sinon, il voit un message d'erreur. Simple et logique.
Le probleme commence quand l'application construit cette requete en concatenant des chaines, en collant directement la saisie de l'utilisateur dans la commande SQL. Le code derriere le formulaire pourrait etre comme ceci :
query = "SELECT * FROM users WHERE username = '" + saisieUtilisateur + "' AND password = '" + saisieMotDePasse + "'"
Cette variable saisieUtilisateur contient ce que l'utilisateur a tape. S'il tape un nom d'utilisateur normal, tout fonctionne. Mais que se passe-t-il s'il tape autre chose ?
Injection SQL classique : l'attaque de base
Au lieu de taper un nom d'utilisateur, un attaquant ecrit ceci dans le champ :
' OR '1'='1' --
L'application colle ceci dans la requete, produisant :
SELECT * FROM users WHERE username = '' OR '1'='1' --' AND password = 'nimportequoi'
Decomposons ce qui s'est passe. L'apostrophe apres la chaine vide ferme la valeur du nom d'utilisateur. Le OR '1'='1' ajoute une condition toujours vraie. Le -- est un marqueur de commentaire SQL, qui dit a la base de donnees d'ignorer tout ce qui suit, y compris la verification du mot de passe. Le resultat : la base de donnees retourne tous les utilisateurs, car '1'='1' est toujours vrai. L'attaquant est connecte, generalement comme le premier utilisateur de la table, qui est souvent l'administrateur.
C'est la forme la plus simple d'injection SQL, et elle a ete utilisee pour compromettre des entreprises de toutes tailles. La breche de Heartland Payment Systems en 2008, qui a expose 130 millions de numeros de cartes de credit, a commence par une attaque par injection SQL.
Extraction de donnees avec les attaques UNION
Le contournement de connexion n'est que le debut. L'utilisation la plus dangereuse de l'injection SQL est l'extraction de donnees. Un attaquant utilise l'operateur SQL UNION pour ajouter des requetes supplementaires a la requete originale et extraire des donnees de n'importe quelle table de la base.
Par exemple, si un site a une recherche de produits qui interroge la base ainsi :
SELECT nom, prix FROM produits WHERE categorie = 'electronique'
Un attaquant peut modifier la saisie en :
electronique' UNION SELECT username, password FROM users --
La requete resultante devient :
SELECT nom, prix FROM produits WHERE categorie = 'electronique' UNION SELECT username, password FROM users --'
Maintenant la page qui devait afficher les produits affiche aussi chaque nom d'utilisateur et mot de passe stockes dans la table des utilisateurs.
Injection SQL aveugle (Blind SQLi)
Toutes les vulnerabilites d'injection SQL ne produisent pas un resultat visible. Parfois l'application n'affiche pas les resultats de la requete sur la page. Dans ces cas, les attaquants utilisent l'injection SQL aveugle, plus lente mais tout aussi efficace.
Blind SQLi basee sur les booleens
L'attaquant envoie des requetes qui posent des questions vrai-ou-faux a la base de donnees. Selon que la page se comporte differemment (affiche du contenu ou une erreur, se charge ou non), l'attaquant deduit un bit d'information a la fois.
Par exemple, pour extraire le premier caractere du mot de passe admin :
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin') = 'a' --
Si la page se charge normalement, le premier caractere est 'a'. Sinon, l'attaquant essaie 'b', puis 'c', et ainsi de suite. Caractere par caractere, il reconstruit le mot de passe entier. Des outils automatises comme sqlmap font cela en quelques minutes.
Blind SQLi basee sur le temps
Quand meme le comportement de la page ne change pas, les attaquants utilisent le timing. Ils injectent des requetes qui font pauser la base de donnees pendant une duree specifique si une condition est vraie :
' AND IF((SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a', SLEEP(5), 0) --
Si la page met 5 secondes a repondre, le premier caractere est 'a'. Si elle repond immediatement, ce n'est pas le cas. Cette technique est plus lente mais fonctionne contre les applications qui montrent des reponses identiques quel que soit le resultat de la requete.
Injection SQL de second ordre
C'est la variante qui surprend meme les developpeurs experimentes. Dans l'injection SQL de second ordre, la saisie malveillante est stockee en securite dans la base de donnees lors de la premiere interaction (par exemple, lors de l'inscription). Elle est correctement echappee lors du stockage. Mais quand cette valeur stockee est ensuite recuperee et utilisee dans une requete differente sans etre a nouveau nettoyee, l'injection s'execute.
Exemple : un utilisateur s'inscrit avec le nom d'utilisateur admin'--. La requete d'inscription utilise des prepared statements, donc la valeur est stockee en securite. Plus tard, l'application a une fonction de changement de mot de passe qui construit une requete ainsi :
UPDATE users SET password = 'nouveaumdp' WHERE username = '" + nomUtilisateurStocke + "'
Quand le nom d'utilisateur stocke admin'-- est place dans cette requete, elle devient :
UPDATE users SET password = 'nouveaumdp' WHERE username = 'admin'--'
L'attaquant vient de changer le mot de passe de l'admin. La saisie a passe la validation initiale parfaitement, mais la seconde utilisation de ces donnees a cree la vulnerabilite.
Ce que les attaquants font apres avoir gagne l'acces
Comprendre les objectifs de l'attaquant aide a saisir pourquoi l'injection SQL est prise si au serieux :
- Exfiltration de donnees : Noms des clients, adresses email, numeros de telephone, historique d'achats, donnees de paiement. C'est l'objectif principal pour la plupart des attaquants.
- Contournement de l'authentification : Se connecter comme administrateur pour obtenir le controle total de l'application.
- Modification de donnees : Changer les prix, alterer les enregistrements de commandes, inserer du contenu malveillant dans les pages servies aux autres utilisateurs.
- Escalade de privileges : Utiliser l'acces a la base de donnees pour lire les fichiers de configuration du serveur ou executer des commandes systeme.
- Deni de service : Supprimer des tables, effacer des enregistrements ou executer des requetes gourmandes en ressources.
Pour une PME suisse, les consequences incluent non seulement les dommages directs mais aussi les violations de la Loi federale sur la protection des donnees (nLPD) si des donnees clients sont exposees a travers une vulnerabilite evitable. Nous avons couvert le cout complet d'une breche dans notre article sur le cout d'un site web pirate pour les PME.
Pourquoi l'injection SQL est encore si repandue
On pourrait se demander comment une vulnerabilite decouverte dans les annees 1990 affecte encore la majorite des applications web. Plusieurs facteurs y contribuent :
- Code legacy : Des sites web construits il y a des annees avec des pratiques de developpement obsoletes tournent encore en production.
- Developpeurs inexperimentes : Tous les developpeurs n'ont pas de formation en securite. Beaucoup apprennent a construire des fonctionnalites d'abord et pensent a la securite ensuite.
- Construction dynamique de requetes : Certaines applications necessitent des requetes complexes qui changent de structure selon les selections de l'utilisateur. Les developpeurs reviennent parfois a la concatenation de chaines quand les prepared statements semblent trop contraignants.
- Fausse securite des ORM : Les frameworks ORM gerent la generation SQL automatiquement, mais les developpeurs peuvent ecrire des requetes brutes quand l'ORM ne supporte pas ce dont ils ont besoin.
- Pas de revue de code ni de tests : Beaucoup de sites PME sont construits par un seul developpeur sans revue de code ni tests de securite.
Breches reelles causees par l'injection SQL
Ce ne sont pas des scenarios theoriques. L'injection SQL a ete derriere certaines des plus grandes breches de donnees de l'histoire :
| Incident | Annee | Impact |
|---|---|---|
| Heartland Payment Systems | 2008 | 130 millions de numeros de cartes de credit voles |
| Sony Pictures | 2011 | 77 millions de comptes PlayStation Network compromis |
| Yahoo | 2012 | 450 000 identifiants divulgues via injection SQL |
| TalkTalk | 2015 | 157 000 enregistrements clients voles, amende de 400 000 GBP |
| Equifax | 2017 | 147 millions d'enregistrements exposes |
Et ce sont les breches qui font les gros titres. Des milliers d'entreprises plus petites sont compromises par injection SQL chaque annee sans aucune divulgation publique. Une petite entreprise a Lugano ou au Tessin avec un formulaire de contact ou un catalogue produits vulnerable est tout aussi exposee qu'une grande entreprise.
Prevention : Prepared Statements (requetes parametrees)
La defense la plus efficace contre l'injection SQL sont les prepared statements, egalement appeles requetes parametrees. Au lieu de construire une chaine SQL en collant la saisie de l'utilisateur, vous definissez la structure de la requete avec des marqueurs et passez la saisie separement :
Vulnerable (concatenation de chaines) :
query = "SELECT * FROM users WHERE username = '" + saisieUtilisateur + "'"
Securise (prepared statement) :
query = "SELECT * FROM users WHERE username = ?" avec parametre [saisieUtilisateur]
Avec un prepared statement, la base de donnees sait que le marqueur est une valeur de donnee, pas une partie de la structure SQL. Meme si l'utilisateur tape ' OR '1'='1' --, la base traite la chaine entiere comme un nom d'utilisateur litteral. L'injection echoue completement.
Chaque langage de programmation moderne et pilote de base de donnees supporte les prepared statements. Il n'y a aucune excuse pour ne pas les utiliser. Si votre developpeur ou agence web construit des requetes par concatenation de chaines, c'est un signal d'alerte serieux sur leurs pratiques de securite.
Prevention : Validation des entrees
Les prepared statements sont la defense principale, mais la validation des entrees ajoute une deuxieme couche. Le principe est simple : definissez a quoi ressemble une saisie valide et rejetez tout le reste.
- Liste blanche plutot que liste noire : Ne tentez pas de filtrer les caracteres dangereux. Definissez plutot ce qui est autorise.
- Verification de type : Si un parametre URL doit etre un entier, convertissez-le en entier avant de l'utiliser.
- Limites de longueur : Les charges utiles d'injection SQL tendent a etre plus longues que les saisies legitimes.
- Encodage de sortie : Meme si l'injection echoue au niveau SQL, l'encodage de sortie empeche le contenu malveillant stocke d'etre interprete comme du code dans le navigateur (ceci recoupe la prevention XSS, que nous couvrons dans notre article XSS explique).
Prevention : Web Application Firewall (WAF)
Un WAF se place entre les utilisateurs et votre application web, inspectant chaque requete a la recherche de modeles ressemblant a des attaques. Les WAF modernes peuvent detecter et bloquer les tentatives d'injection SQL en temps reel.
Un WAF est une couche de defense precieuse, mais ce n'est pas un substitut a l'ecriture de code securise. Les WAF peuvent etre contournes. Pensez a un WAF comme un filet de securite, pas un remplacement pour construire la maison correctement.
- WAF cloud : Cloudflare, Sucuri, AWS WAF. Les plus faciles a deployer.
- WAF au niveau serveur : ModSecurity avec OWASP Core Rule Set.
- WAF au niveau application : Bibliotheques et middleware qui inspectent les requetes dans le code applicatif.
Prevention : Acces a la base de donnees avec privileges minimaux
Meme si un attaquant reussit a injecter du SQL, vous pouvez limiter les degats en restreignant ce que l'utilisateur de base de donnees peut faire. Le compte de base de donnees de l'application devrait avoir les permissions minimales necessaires pour fonctionner.
- Si l'application ne fait que lire des donnees d'une table, l'utilisateur ne devrait pas avoir de permissions d'ecriture sur cette table.
- L'utilisateur ne devrait jamais avoir les permissions
DROP TABLEouDROP DATABASE. - Les operations administratives devraient utiliser un compte separe et plus privilegie.
- Envisagez d'utiliser des utilisateurs differents pour differentes parties de l'application.
Que faire si vous suspectez que votre site est vulnerable
- Ne paniquez pas, mais agissez vite. L'injection SQL est serieuse mais reparable.
- Demandez directement a votre developpeur ou agence : "Utilisons-nous des prepared statements pour toutes les requetes de base de donnees ?"
- Lancez un scan automatise. OWASP ZAP est gratuit et peut identifier les modeles d'injection SQL les plus courants.
- Deployez un WAF immediatement. Le plan gratuit de Cloudflare inclut une protection WAF de base.
- Verifiez vos logs. Cherchez des requetes contenant des mots-cles SQL comme
UNION,SELECT,DROP. - Priorisez la correction. N'attendez pas le prochain cycle de developpement.
Pour une vue plus large des vulnerabilites des applications web, consultez notre analyse de l'OWASP Top 10. Et si vous souhaitez une evaluation professionnelle de votre site, contactez notre equipe a Lugano.
Le point essentiel pour les dirigeants
L'injection SQL n'est ni exotique ni sophistiquee. C'est une vulnerabilite bien comprise avec des defenses bien comprises. Le fait qu'elle apparaisse encore dans la majorite des applications web est un echec des pratiques de developpement, pas un manque de solutions disponibles.
Si votre site a une base de donnees derriere lui (et s'il a un formulaire de connexion, une fonction de recherche, un catalogue produits ou un formulaire de contact qui stocke les soumissions, c'est presque certainement le cas), posez la question : comment nos requetes de base de donnees sont-elles construites ? La reponse devrait toujours etre "avec des prepared statements." Toute autre reponse est un risque que votre entreprise ne devrait pas porter.
Vous voulez savoir si votre site est sécurisé ?
Demandez un audit de sécurité gratuit. En 48 heures vous recevez un rapport complet.
Demander un Audit Gratuit