- Catégorie OWASP
- A03 Injection (Top 10 2021)
- CWE
- CWE-89 (Improper Neutralization of Special Elements in SQL)
- Apparition publique
- Vers 1998 — articles de Jeff Forristal (Rain Forest Puppy)
- Méthode de protection clé
- Requêtes préparées avec paramètres liés
- Incident majeur récent
- MOVEit Transfer 2023 — 2 700+ organisations impactées
01 — DéfinitionQu'est-ce qu'une injection SQL ?
L'injection SQL fait partie de la catégorie A03 du Top 10 OWASP. Pour le panorama complet des failles applicatives et leur prévention, voir notre guide OWASP & failles applicatives.
Une injection SQL (SQL injection, souvent abrégée SQLi) est une attaque applicative qui consiste à injecter du code SQL malveillant dans les entrées d'une application web pour manipuler la base de données sous-jacente.
Le problème racine : l'application construit ses requêtes SQL en concaténant directement des entrées utilisateur non filtrées, ce qui permet à un attaquant de détourner la syntaxe SQL pour y insérer ses propres commandes.
Exemple minimal
Un formulaire de connexion mal codé :
// PHP vulnérable — À NE JAMAIS FAIRE
$user = $_POST['username'];
$pass = $_POST['password'];
$query = "SELECT * FROM users WHERE username='$user' AND password='$pass'";
$result = mysqli_query($conn, $query);
Un attaquant entre comme nom d'utilisateur :
admin'--
La requête devient :
SELECT * FROM users WHERE username='admin'--' AND password='nimportequoi'
Le -- est un commentaire SQL. Tout ce qui
suit est ignoré. La vérification du mot de passe est
complètement contournée. L'attaquant
se connecte comme admin sans en connaître
le mot de passe.
Conséquences possibles
- Lecture non autorisée : extraction de données sensibles (clients, mots de passe hashés, CB).
- Contournement d'authentification : connexion sans identifiants valides.
- Modification de données : changement de soldes, droits, prix.
- Suppression de données :
DROP TABLE, destruction volontaire. - Extraction de base complète : dump de tables entières via outils comme sqlmap.
- Exécution de commandes système dans certains cas :
xp_cmdshellsur SQL Server,LOAD_FILEetINTO OUTFILEsur MySQL mal configurés. - Pivoting : utilisation du serveur SQL comme point de départ pour attaquer le reste du réseau.
- Atteinte à la disponibilité : requêtes lourdes provoquant déni de service.
Pourquoi cette attaque existe depuis 30 ans ?
Plusieurs raisons structurelles :
- Conception historique du SQL : pas de distinction native entre code et données dans les requêtes construites par concaténation.
- Frontière applicative complexe : multiples points d'entrée utilisateur, toutes les entrées ne sont pas toujours sécurisées.
- Code legacy : applications des années 2000 non refactorisées.
- Formation insuffisante : développeurs junior confrontés à du SQL brut.
- Complexité des applications modernes : ORM parfois contournés pour des requêtes sur-mesure.
- Logique dynamique : tri, filtres, recherche avancée qui nécessitent du SQL construit dynamiquement — pièges fréquents.
Classement OWASP
Historiquement #1 du Top 10 OWASP pendant longtemps (2010, 2013, 2017). Depuis 2021, fusionnée dans la catégorie A03 Injection qui regroupe SQLi, XSS, command injection, LDAP injection, NoSQL injection, etc. Le déplacement ne signifie pas que la SQLi est moins dangereuse — mais que les autres types d'injection méritent aussi d'être traités collectivement.
L'injection SQL est à la cybersécurité applicative ce que le phishing est à l'ingénierie sociale : connue depuis toujours, parfaitement documentée, totalement évitable techniquement, et pourtant toujours responsable de catastrophes majeures. Le problème n'est pas le savoir mais son application.
02 — FonctionnementAnatomie d'une injection SQL
Les 3 étapes d'une SQLi
1. Identification d'un point d'injection
L'attaquant teste des entrées qui pourraient être intégrées dans une requête SQL :
- Paramètres d'URL :
?id=42 - Champs de formulaire : login, recherche.
- Headers HTTP : User-Agent, Referer, Cookie.
- Données d'API : corps JSON, XML.
- Champs dans des uploads de fichiers.
Test initial classique : injecter une apostrophe
' et observer. Si l'application renvoie une
erreur SQL, indice fort. Pour les « blind SQLi »,
pas d'erreur visible — l'attaquant infère via des
conditions booléennes ou des délais de réponse.
2. Construction du payload
L'attaquant construit une entrée qui détourne la syntaxe SQL. Primitives courantes :
'ou": casser la chaîne.--ou#: commenter la fin de la requête.OR 1=1: forcer une condition vraie.UNION SELECT: ajouter des colonnes issues d'autres tables.;: séparer pour ajouter une nouvelle requête (stacked queries).- Fonctions système :
version(),user(),database().
3. Exploitation
Une fois l'injection confirmée, l'attaquant exfiltre progressivement :
- Identification du SGBD (MySQL, PostgreSQL, SQL Server, Oracle) et de sa version.
- Énumération des tables et colonnes via information_schema ou équivalent.
- Extraction des données table par table.
- Souvent automatisée avec sqlmap, outil open source de référence (~2-30 min pour dumper une base complète selon la taille).
Exemples de payloads classiques
Contournement d'authentification
-- Entrée : admin'--
SELECT * FROM users WHERE username='admin'--' AND password='...'
-- Entrée : ' OR '1'='1
SELECT * FROM users WHERE username='' OR '1'='1' AND password='...'
UNION-based — extraction de données
-- Paramètre : 1 UNION SELECT username, password FROM users
SELECT name, description FROM products WHERE id=1
UNION SELECT username, password FROM users
Stacked queries (selon SGBD)
-- Paramètre : 1; DROP TABLE users--
SELECT * FROM products WHERE id=1; DROP TABLE users--
Time-based blind
-- Paramètre : 1 AND (SELECT CASE WHEN (user()='root') THEN SLEEP(5) ELSE 0 END)
-- Si réponse lente = condition vraie = utilisateur est root
Le rôle de sqlmap
sqlmap est l'outil de test SQLi de référence, open source, disponible partout. Il automatise : détection de vulnérabilité, identification du SGBD, énumération de bases/tables/colonnes, extraction de données, extraction de hashs et tentative de cassage, dans certains cas exécution de commandes OS. Utilisé légitimement par les pentesters et par les attaquants. Un pentest professionnel ne peut pas se passer de sqlmap.
Ce qui permet une SQLi
Condition nécessaire et suffisante : des données utilisateur intégrées dans une requête SQL sans mécanisme de séparation code/données. Ce mécanisme de séparation existe depuis très longtemps (prepared statements) mais son usage n'est pas systématique.
03 — TypesLes grandes familles d'injections SQL
1. In-band SQLi (classique)
L'attaquant utilise le même canal pour injecter et recevoir les résultats. Le plus direct et facile à exploiter.
Error-based
Exploite les messages d'erreur SQL renvoyés par l'application pour extraire des informations. Exemple : forcer une erreur de conversion qui révèle la valeur d'une colonne. Particulièrement efficace quand l'application affiche des erreurs techniques en production — une mauvaise pratique qui reste courante.
UNION-based
Utilise l'opérateur SQL UNION pour combiner
les résultats de la requête légitime avec une requête
contrôlée par l'attaquant. Méthode la plus efficace
pour exfiltrer des données massives.
2. Blind SQLi (aveugle)
L'application ne renvoie pas directement les résultats ni les erreurs. L'attaquant doit inférer les informations via des conditions.
Boolean-based blind
L'attaquant injecte des conditions qui modifient le comportement de l'application (page qui s'affiche normalement vs erreur générique). En posant des questions binaires successives (« la première lettre du nom de l'admin est-elle plus grande que M ? »), il extrait les données caractère par caractère.
Time-based blind
L'attaquant injecte des commandes qui provoquent un
délai (SLEEP(5), WAITFOR DELAY)
conditionnellement. Si la page répond lentement, la
condition est vraie. Plus lent mais plus universel.
3. Out-of-band SQLi (OOB)
Utilisé quand les canaux classiques sont inutilisables. L'attaquant fait déclencher une requête externe par le serveur de base de données vers un serveur qu'il contrôle : DNS, HTTP. L'exfiltration passe par ce canal secondaire. Techniques :
- MySQL :
LOAD_FILEavec chemin UNC. - SQL Server :
xp_dirtreevers un partage SMB attaquant. - Oracle :
UTL_HTTP,UTL_INADDR.
Technique souvent utilisée en environnements avec WAF strict bloquant les réponses SQL suspectes.
4. Second-order SQLi
L'entrée malveillante est stockée d'abord (ex. dans un champ profil utilisateur), puis déclenchée plus tard quand elle est utilisée dans une autre requête. Contourne les validations à l'insertion qui supposent que les données en base sont « propres ».
5. NoSQL injection
Cousine moderne ciblant les bases NoSQL : MongoDB,
CouchDB, Cassandra. Syntaxe différente mais logique
identique : injection de structure JSON/BSON,
opérateurs malveillants ($ne, $gt
en MongoDB), équivalent
des bypass d'authentification classiques. Incluse dans
la catégorie OWASP A03 Injection.
Autres injections apparentées
- LDAP injection : dans les requêtes Active Directory/LDAP.
- Command injection / OS injection : injection dans shell système.
- XPath injection : dans XML.
- Template injection (SSTI) : dans moteurs de templates (Jinja, Twig, Velocity).
- ORM injection : dans requêtes dynamiques ORM mal utilisés.
- Header injection : CRLF, SMTP.
Toutes partagent le même problème racine — des entrées utilisateur interprétées comme code plutôt que données.
04 — ExemplesIncidents historiques marquants
Heartland Payment Systems (2008)
Processeur de paiement américain compromis via SQLi. 134 millions de cartes bancaires volées, l'un des plus gros incidents financiers de l'histoire. Coût total pour Heartland : 140 M USD. Auteur principal Albert Gonzalez condamné à 20 ans de prison. Alimenté par une chaîne d'injections SQL sur plusieurs sites web commerciaux pour récupérer les données de CB traitées.
Sony Pictures (2011)
Compromise par le groupe LulzSec via SQLi sur le site sonypictures.com. Vol d'1 million de comptes avec mots de passe stockés en clair (scandale supplémentaire). LulzSec a publiquement utilisé l'incident pour illustrer les mauvaises pratiques de Sony. Plusieurs membres arrêtés par la suite.
TalkTalk UK (2015)
Opérateur télécom britannique victime de SQLi sur un formulaire de contact obsolète hérité d'un ancien site. 157 000 clients exposés, 15 600 avec coordonnées bancaires. Amende record de 400 000 £ par l'ICO (Information Commissioner's Office). PDG Dido Harding a démissionné ultérieurement. Plusieurs adolescents britanniques condamnés — l'attaque initiale avait été menée par des mineurs utilisant des outils basiques. Illustre le risque du code legacy oublié.
Yahoo (2012-2014)
Série de breaches massifs chez Yahoo cumulant 3 milliards de comptes compromis sur plusieurs années. Plusieurs vecteurs dont SQLi parmi les premiers. Impact sur valorisation lors du rachat par Verizon (350 M USD de réduction). Sanctions SEC ultérieures pour défaut de divulgation.
Panama Papers (2016)
La fuite historique de 11,5 millions de documents de Mossack Fonseca aurait été obtenue, selon des rapports techniques, via l'exploitation de multiples vulnérabilités dont des SQLi sur leurs interfaces web mal maintenues (WordPress et Drupal obsolètes avec plugins vulnérables). Cabinet panaméen spécialisé en sociétés offshore finalement liquidé en 2018.
Equifax (2017) — cas connexe
Pas une SQLi directe mais Apache Struts CVE-2017-5638 exploitée pour exécuter des requêtes SQL sur 147 millions de dossiers (citoyens américains, britanniques, canadiens). Coût pour Equifax : 1,4 milliard USD (règlements, amendes, litigation). PDG démissionnaire. Cas emblématique d'une application vulnérable (Struts) conduisant à un accès SQL massif.
MOVEit Transfer (mai-juin 2023)
L'incident SQLi majeur récent. MOVEit, logiciel de transfert de fichiers utilisé par des milliers de grandes organisations, compromis via CVE-2023-34362, SQLi zero-day exploité par le groupe Cl0p. Impact massif :
- 2 700+ organisations touchées dans le monde.
- 93+ millions de personnes dont les données ont été exposées.
- Victimes notables : BBC, British Airways, Aer Lingus, US Department of Energy, Université de Californie, Shell, Ernst & Young, PwC, Deloitte (via clients), Sony, plusieurs états américains.
- Coût estimé : plusieurs milliards USD au total sur 2023-2024.
- Cl0p a publié les données volées sur son leak site .onion quand les victimes refusaient de payer.
Démontre qu'en 2023, des SQLi critiques peuvent encore être découvertes sur des produits largement déployés dans les infrastructures critiques mondiales.
Leçons récurrentes
- Code legacy : TalkTalk, Panama Papers — les applications anciennes non refactorisées sont des bombes à retardement.
- Systèmes en bordure : MOVEit — les produits exposés à Internet avec accès base de données sont cibles privilégiées.
- Exploitation massive rapide : Cl0p a exploité MOVEit CVE quelques heures après disponibilité de l'exploit, avant que la majorité des clients ne patchent.
- Pentests réguliers essentiels : beaucoup de ces SQLi auraient été détectées par un pentest moderne.
- Impact hors-proportion : une seule vulnérabilité peut compromettre des dizaines de millions de personnes.
05 — ProtectionComment se protéger efficacement
Prepared statements avec paramètres liés : le SQL est pré-compilé avec des placeholders, les valeurs utilisateur sont transmises séparément et traitées comme données strictes, jamais interprétées comme code. Protection structurelle, pas juste filtrage.
// PHP avec PDO — correct
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$user, $hash_password]);
// Java avec PreparedStatement — correct
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE username = ? AND password = ?");
ps.setString(1, user);
ps.setString(2, hashPassword);
// Python avec psycopg2 — correct
cur.execute(
"SELECT * FROM users WHERE username = %s AND password = %s",
(user, hash_password)
)
// Node.js avec mysql2 — correct
connection.execute(
"SELECT * FROM users WHERE username = ? AND password = ?",
[user, hashPassword]
);
Même si l'utilisateur entre admin'--,
c'est traité comme la chaîne littérale cherchée,
pas comme du SQL. Protection par construction.
- Les ORM modernes (Hibernate Java, Eloquent Laravel, Prisma Node, SQLAlchemy Python, Entity Framework .NET) génèrent des requêtes sécurisées par défaut.
- Attention aux requêtes natives : raw queries, native queries contournent l'ORM et peuvent réintroduire des SQLi si mal utilisées.
- Validation type-safe : Prisma, Drizzle en TypeScript forcent des types stricts qui éliminent beaucoup de risques.
- Méthodes query builder : souvent plus sûres que raw, à condition de ne pas concaténer.
- Type : si une entrée est censée être un entier (ID), la convertir explicitement en integer avant tout usage.
- Format : regex stricts pour emails, codes postaux, identifiants.
- Plage : valeurs dans les bornes attendues.
- Liste blanche quand possible : enum de valeurs acceptables plutôt que blacklist.
- Jamais de confiance aux validations côté client : contournables en 30 secondes avec Burp ou curl.
- WAF : règles anti-SQLi type ModSecurity CRS, Cloudflare, AWS WAF. Protection complémentaire, jamais substituable à du code sûr.
- Moindre privilège sur le compte BDD applicatif : l'application ne doit pas se connecter en admin. Permissions SELECT/INSERT/UPDATE/DELETE uniquement sur les tables nécessaires, pas de DROP ni CREATE.
- Comptes distincts par fonction : compte lecture-seule pour reporting, compte écriture limité pour l'app.
- Pas de fonctions dangereuses exposées : désactiver
xp_cmdshellsur SQL Server, limiterLOAD_FILE/INTO OUTFILEsur MySQL. - Monitoring des requêtes anormales : alertes sur patterns suspects, requêtes trop longues, nombreuses erreurs.
- Logs protégés : remontés vers SIEM, immuables.
- Formation développeurs : OWASP SQL Injection Prevention Cheat Sheet est la référence, lectures obligatoires.
- Code review : recherche active de concaténations SQL suspectes.
- SAST (analyse statique) : SonarQube, Semgrep, Checkmarx détectent les patterns SQLi dans le code.
- DAST avec OWASP ZAP ou Burp en pipeline CI/CD.
- Pentest manuel : annuel minimum, plus si changements majeurs.
- Bug bounty : programmes HackerOne, YesWeHack pour crowdsourced discovery.
- «
mysqli_real_escape_stringsuffit » : FAUX. L'échappement de guillemets ne couvre pas tous les contextes (ORDER BY, LIMIT). Prepared statements sont plus sûrs. - Filtrage par blacklist : rechercher et bloquer
UNION,SELECT. Contournable avec encodages, casse, commentaires. - Stored procedures = sécurité : FAUX. Les stored procs concaténant des entrées sont aussi vulnérables.
- Validation uniquement côté client : contournée en 30 secondes.
- ORM = protection absolue : FAUX. Les raw queries dans un ORM peuvent être vulnérables.
- WAF seul suffit : FAUX. Les WAF sont contournables, ils doivent être complémentaires au code sécurisé.
- Obscurité = sécurité : masquer les noms de tables, cacher les colonnes ne protège pas. Un attaquant avec SQLi peut énumérer le schéma.
06 — DétectionIdentifier et auditer
Comment tester son application
Tests manuels
Pour un développeur ou pentester junior, commencer par :
- Injecter une apostrophe
'dans chaque champ — observer si une erreur SQL apparaît. - Tester
' OR '1'='1dans les champs de connexion. - Essayer
1 AND 1=1vs1 AND 1=2dans les paramètres numériques — comportement différent = indice. - Tester
1 AND SLEEP(5)et chronométrer. - Explorer tous les endpoints, pas seulement les plus visibles.
Outils automatisés
- sqlmap : référence de test SQLi automatisé.
sqlmap -u "https://target.com/page?id=1". Peut identifier, exploiter et dumper. Utilisé massivement par les pentesters légitimes et les attaquants. - OWASP ZAP : active scan détecte les SQLi classiques, gratuit.
- Burp Suite (Professional) : scanner intégré, tests manuels assistés. Standard des pentesters.
- Nuclei : templates SQLi en scan rapide, ProjectDiscovery.
- Wapiti, Nikto : scanners libres moins puissants mais utilisables.
SAST (Static Application Security Testing)
Analyse le code source sans exécuter l'application. Détecte les patterns dangereux :
- SonarQube : règles de sécurité intégrées, édition Community gratuite limitée.
- Semgrep : open source, règles custom faciles, CI/CD friendly.
- Checkmarx, Veracode, Fortify : solutions commerciales enterprise.
- CodeQL (GitHub) : gratuit pour l'open source, puissant.
- Bandit (Python), GoSec (Go), linters spécialisés.
Bug bounty et pentest
Les SQLi se paient bien dans les programmes bug bounty :
- SQLi critique sur app majeure : 5 000 à 30 000 USD courants.
- Plateformes : HackerOne, Bugcrowd, YesWeHack (francophone).
- Rapports annuels : SQLi toujours dans le top 10 des vulnérabilités payées.
Détection runtime
- WAF : blocage ou alerte sur patterns d'injection. Contournable mais utile pour détecter tentatives massives.
- Logs applicatifs : erreurs SQL fréquentes, patterns suspects dans les paramètres.
- Logs base de données : requêtes anormalement complexes, utilisation de
UNIONsur tables système. - SIEM + UEBA : corrélation et détection d'anomalies comportementales.
- Honeypots : tables pièges avec noms tentants (admins, credentials) pour détecter l'exploration par un attaquant post-SQLi.
Audit des applications existantes
Pour évaluer un parc d'applications :
- Inventorier toutes les applications web et leurs technologies.
- Prioriser par exposition (Internet, intranet) et sensibilité des données.
- Scan automatisé systématique (ZAP, sqlmap).
- Pentests ciblés sur les plus critiques.
- Analyse statique sur le code legacy accessible.
- Vérifier les interfaces d'administration cachées, API legacy.
- Contrôler les permissions base de données.
Indicateurs qu'une SQLi est en cours ou a eu lieu
- Pics de requêtes étranges vers les endpoints.
- Utilisation anormale de
UNION,INFORMATION_SCHEMA. - Multiples erreurs SQL dans les logs.
- Requêtes avec commentaires SQL inhabituels (
--,/*). - Volumes de données extraits inhabituels depuis l'app.
- Accès à des tables sensibles hors du pattern normal.
- Apparition de données confidentielles sur le dark web.
07 — FAQQuestions fréquentes
Pourquoi les injections SQL restent-elles si fréquentes après 30 ans ?
Quelques raisons persistantes : code legacy — les applications des années 2000 non refactorisées sont encore en production partout. Formation insuffisante — beaucoup de tutoriels en ligne montrent encore des concaténations SQL dangereuses. Complexité moderne — API, microservices, multiplication des points d'entrée multiplient les opportunités. Requêtes dynamiques nécessaires — tri, filtres avancés, recherche full-text parfois mal implémentés contournent l'ORM. Pressure commerciale — release fréquentes, tests sécurité parfois superficiels. Les SQLi sont en déclin relatif grâce aux ORM et frameworks modernes, mais loin d'avoir disparu.
Les NoSQL sont-elles immunisées contre les injections ?
Non, elles ont leurs propres vulnérabilités. Les bases
NoSQL (MongoDB, CouchDB, Elasticsearch) ne parlent pas
SQL mais acceptent des requêtes structurées (JSON,
BSON) qui peuvent être manipulées. Exemple MongoDB :
l'opérateur {"$ne": null} injecté à la place
d'une valeur peut contourner une authentification si la
requête est construite dynamiquement. Les attaques JS
server-side injection sont aussi possibles sur certaines
configurations MongoDB anciennes. La NoSQL injection
est explicitement incluse dans la catégorie OWASP A03
Injection. Les principes de protection sont identiques :
pas de concaténation d'entrées non validées, utiliser
les drivers ORM/ODM avec paramétrage sûr, valider les
types côté serveur.
Un WAF suffit-il à bloquer les SQLi ?
Non, un WAF est une couche de défense complémentaire, jamais substituable à du code sûr. Les WAF modernes (Cloudflare, F5, Imperva, ModSecurity) bloquent la majorité des payloads SQLi classiques, mais les attaquants utilisent régulièrement des techniques de contournement : encodage (URL, Unicode, hexadécimal), tirer parti des différences parsing entre WAF et application, SQLi via headers HTTP ou paramètres moins contrôlés, injection fragmentée sur plusieurs requêtes. Le WAF est une couche utile pour bloquer les scans automatisés et les tentatives grossières, pour détecter et alerter. Mais une application sûre doit l'être par construction (prepared statements), pas seulement protégée par un WAF.
Combien coûte une injection SQL quand elle est exploitée ?
Très variable mais souvent massif. Études IBM Cost of a Data Breach 2024 : coût moyen d'une violation de données : 4,88 M USD (toutes causes confondues, moyennes). Cas SQLi spécifiques : TalkTalk 2015 : 60 M£ de coûts directs + dommages réputation. Heartland 2008 : 140 M USD directs. Equifax 2017 : 1,4 milliard USD cumulés. MOVEit 2023 : coûts partagés entre milliers d'organisations impactées, total estimé à plusieurs milliards USD. Composantes du coût : notification clients (RGPD 72h), forensic, remédiation, amendes CNIL/DPA (jusqu'à 4% du CA annuel mondial), litigation, perte de clients, chute de cours (pour les entreprises cotées).
L'IA va-t-elle faire disparaître les SQLi ?
Partiellement mais pas complètement. Côté défense : les assistants IA (GitHub Copilot, Cursor, Claude Code) génèrent souvent du code avec prepared statements par défaut, ce qui pousse les bons patterns. Les outils SAST augmentés par IA détectent mieux les patterns complexes. Les WAF nouvelle génération analysent sémantiquement les requêtes. Côté attaque : l'IA accélère aussi les attaquants, peut aider à découvrir des SQLi plus rapidement, à contourner des filtres classiques. Globalement la tendance reste à la diminution des SQLi grâce aux frameworks modernes et à la sensibilisation, mais elles ne disparaîtront pas tant que du code legacy existera et que la pression développement permettra des raccourcis dangereux.
Je suis développeur, par où commencer pour éviter les SQLi ?
Plan d'action pratique : 1. Lire la OWASP SQL Injection Prevention Cheat Sheet (30 minutes, la référence mondiale). 2. Refactoriser toutes les concaténations SQL en prepared statements, dans l'ordre de criticité. 3. Activer un linter/SAST qui détecte les patterns dangereux (Semgrep, SonarQube Community, ESLint-plugin-security). 4. Intégrer OWASP ZAP en pipeline CI pour les tests automatisés. 5. Faire un pentest ou bug bounty une fois le refactoring fait. 6. Former l'équipe avec OWASP Juice Shop ou WebGoat en exercice pratique. 7. Principe de moindre privilège sur la base — le compte applicatif ne doit jamais pouvoir DROP ou CREATE. Éviter à tout prix : chercher à « nettoyer » les entrées avec des blacklists, utiliser des fonctions d'échappement seules, considérer qu'un ORM protège automatiquement contre toutes les requêtes (raw queries restent à risque).