TL;DRL'injection est la famille de failles la plus ancienne et la plus rentable pour un pirate : il glisse du code dans un champ de saisie, et le site l'exécute à la place du visiteur. Voici comment elle fonctionne, comment l'éviter et ce que nous mettons en place sur nos serveurs.

Qu'est-ce qu'une faille d'injection ?#

Une injection survient quand une application construit une requête, une commande ou une page en y collant du texte venu de l'extérieur sans le contrôler. L'interpréteur (base de données, système, navigateur) ne sait pas distinguer le texte légitime du texte piégé : il exécute les deux.

Schéma d'une injection : la saisie d'un visiteur est interprétée comme une commande par la base de données
Une saisie non filtrée devient une instruction.

Injection SQL#

Le texte saisi modifie la requête envoyée à la base de données. Un formulaire de connexion mal codé en est l'exemple classique :

// À NE PAS FAIRE : la saisie est collée dans la requête
$sql = "SELECT * FROM users WHERE email = '" . $_POST['email'] . "'";

Si le visiteur saisit une valeur qui ferme l'apostrophe et ajoute sa propre condition, la requête change de sens et peut renvoyer tous les comptes, ou ne plus vérifier le mot de passe.

Injection de commandes#

Le site transmet une saisie à une commande système (conversion d'image, ping, génération de PDF). Un point-virgule ou un opérateur de commande ajouté dans la saisie permet d'enchaîner une seconde commande, avec les droits du serveur web.

XSS (Cross-Site Scripting)#

Ici, la cible n'est pas le serveur mais les autres visiteurs. Le pirate fait afficher du JavaScript par une page (commentaire, avis, champ de recherche reflété). Le navigateur de la victime l'exécute avec les droits de la page : vol de cookie de session, redirection, faux formulaire.

Pourquoi les assaillants les utilisent#

  • Elles sont automatisables : des outils testent des milliers de sites par heure sur les paramètres d'URL et les formulaires.
  • Elles donnent accès aux données : comptes clients, emails, commandes, parfois les hachages de mots de passe.
  • Elles peuvent ouvrir la porte du serveur : une injection de commandes équivaut à une exécution de code à distance.
  • Elles se monétisent facilement : revente de bases, spam, hébergement de pages d'hameçonnage, minage.

Cas concret : le moteur de recherche d'une boutique#

Scénario illustratif. Une boutique en ligne propose un champ de recherche qui affiche « Résultats pour : » suivi du terme saisi, et qui compose sa requête SQL par concaténation. Un robot envoie des caractères spéciaux dans ce champ. Deux constats : la page renvoie une erreur SQL détaillée, et le terme est réaffiché sans échappement. Le robot confirme ainsi une injection SQL et une XSS en quelques secondes, puis automatise l'extraction de la table clients.

Cas d'usage typiques à surveiller#

  • Formulaires de contact, d'inscription, de connexion.
  • Champs de recherche et filtres de catalogue (paramètres dans l'URL).
  • Commentaires, avis, profils : tout ce qui est affiché à d'autres utilisateurs.
  • Outils qui lancent des programmes (conversion, redimensionnement, export).
  • Imports de fichiers CSV ou XML.

Comment s'en prémunir#

Côté code#

  • Requêtes préparées pour toute requête SQL : la saisie est transmise comme valeur, jamais comme code.
  • Échappement en sortie : tout texte affiché dans une page doit être échappé (les moteurs de gabarits comme Twig le font par défaut).
  • Validation des entrées : liste de valeurs autorisées plutôt que liste d'interdits.
  • Pas de commande système avec une saisie : utilisez une bibliothèque, ou transmettez les arguments sous forme de tableau sans passer par un shell.
  • Erreurs masquées en production : jamais de message SQL détaillé visible par le visiteur.
Schéma d'une requête préparée : la saisie reste une donnée et n'est jamais exécutée
Avec une requête préparée, la saisie ne devient jamais une instruction.
// Requête préparée avec PDO
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $_POST['email']]);

Avec Doctrine (Symfony), les méthodes findBy() et le QueryBuilder avec paramètres nommés appliquent ce principe automatiquement. Le risque revient dès qu'on concatène du texte dans une requête DQL ou SQL brute.

Côté base de données#

  • Un compte applicatif aux droits minimaux : pas de droit d'administration, pas d'accès aux autres bases.
  • Une base accessible uniquement depuis les adresses qui en ont besoin.

Ce que nous configurons sur nos serveurs#

Le code reste la première défense, mais le serveur ajoute des couches utiles contre l'exploitation des injections.

En-têtes de sécurité Apache#

Ils limitent les dégâts d'une XSS (type de contenu forcé, intégration dans des cadres restreinte, règles de chargement des scripts) :

Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "same-origin"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

Nous déployons aussi une Content-Security-Policy. Nous l'avons d'abord mise en mode rapport (Content-Security-Policy-Report-Only) : le navigateur signale les violations sans rien bloquer, ce qui permet de corriger les scripts légitimes avant de passer en mode bloquant.

Blocage des scanners connus#

Les outils d'attaque automatisés s'identifient souvent par leur User-Agent. Nous refusons les plus courants :

<If "%{HTTP_USER_AGENT} =~ /(zgrab|masscan|nmap|SecurityScanner)/i">
    Require all denied
</If>

Ce filtre ne remplace pas la correction du code, un pirate sérieux change son User-Agent, mais il écarte le bruit de fond.

Pas de fuite d'informations#

  • ServerTokens Prod et ServerSignature Off : Apache n'affiche plus sa version.
  • Profileur de débogage bloqué en production pour tout le monde.
  • Erreurs détaillées désactivées hors environnement de développement.

Limiter la casse en cas d'exécution de code#

Dans les dossiers qui reçoivent des fichiers déposés par les visiteurs, nous interdisons l'exécution de tout script, ce qui neutralise une injection qui déposerait un fichier piégé (voir l'article sur la mauvaise configuration).

Les erreurs fréquentes#

  • Filtrer à la main quelques caractères (« remplacer l'apostrophe ») au lieu d'utiliser des requêtes préparées.
  • Échapper à l'entrée plutôt qu'à la sortie : l'échappement dépend du contexte d'affichage.
  • Désactiver l'échappement d'un gabarit « pour que le HTML s'affiche ».
  • Ne tester que le formulaire visible : les paramètres cachés et les en-têtes sont aussi des entrées.

Questions fréquentes#

Un pare-feu applicatif (WAF) suffit-il contre les injections ?#

Non. Un WAF réduit l'exposition aux attaques connues mais peut être contourné. La correction du code, avec requêtes préparées et échappement, reste indispensable.

Mon CMS est-il concerné ?#

Oui, via ses extensions et thèmes. Le noyau est généralement bien audité, les modules tiers beaucoup moins. Gardez-les à jour et supprimez ceux que vous n'utilisez pas.

Comment savoir si mon site est vulnérable ?#

Par un audit de code et des tests d'intrusion, ou au minimum un scanner de vulnérabilités sur un environnement de test. Les erreurs SQL visibles dans les pages sont un signal d'alerte.

La XSS est-elle moins grave que l'injection SQL ?#

Elle ne vise pas le serveur mais les visiteurs. Sur un site à comptes, elle permet pourtant de voler des sessions, y compris celles d'un administrateur.

Article rédigé le 04/10/2026 par l'équipe Websource à partir des sources citées ci-dessus, puis relu avant publication. Une information vous semble inexacte ou datée ? Signalez-le nous, nous corrigeons.