Guide des technologies

Protection contre les injections SQL : guide pratique

7 min read Cybersécurité Mis à jour 27 Sep 2025
Protéger contre les injections SQL
Protéger contre les injections SQL

Capture d'écran conceptuelle d'une injection SQL montrée sur un écran d'ordinateur

SQL (Structured Query Language) est le langage standard pour interroger et modifier des bases de données relationnelles. Une injection SQL se produit quand un attaquant transmet des fragments SQL non filtrés qui sont ensuite exécutés par la base, entraînant fuite, altération ou suppression de données.

Ce guide explique comment fonctionne une injection SQL et donne des contre-mesures pratiques que vous pouvez appliquer immédiatement. Il inclut aussi des exemples dans plusieurs langages, des checklists par rôle, un playbook d’incident et des cas de tests pour valider la protection.

Comment se produit une injection SQL

Une injection SQL survient lorsque l’application construit dynamiquement une requête SQL en concaténant des données d’entrée utilisateurs sans les traiter. Si l’entrée contient des caractères spéciaux (quotes, points-virgules, commentaires), l’attaquant peut modifier la logique de la requête.

Exemple vulnérable en PHP (code simplifié)

Si l’utilisateur saisit username = computer et password = comp123, la requête devient normale. Mais si un attaquant met en password une chaîne comme ' OR 'a'='a, la condition devient toujours vraie et l’attaquant obtient l’accès sans crédentials valides.

Important — Définition rapide

  • Injection SQL : insertion de code SQL malveillant dans une entrée utilisateur qui est exécutée par la base.

Principes de base pour protéger votre base de données

  1. Assainir et valider les entrées.
  2. Privilèges minimum pour les comptes de connexion.
  3. Utiliser des requêtes paramétrées (prepared statements).
  4. Ne pas révéler les messages d’erreur détaillés aux utilisateurs.
  5. Mettre en place détections, journaux et alertes.

Assainir et valider les entrées

Assainir (sanitization) = neutraliser les caractères spéciaux dangereux. Valider (validation) = vérifier que la valeur correspond au format attendu (longueur, type, motif).

Bonnes pratiques :

  • Utiliser une validation en liste blanche (ex : regex pour email, numériques uniquement pour IDs).
  • Supprimer espaces inutiles, retours à la ligne et contrôles invisibles.
  • Refuser les caractères non autorisés selon le champ.
  • Ne pas remplacer la validation par un simple escape — privilégiez les requêtes paramétrées.

Exemple d’utilisation de mysqli_real_escape_string en PHP (correct mais inférieur aux requêtes paramétrées) :

real_escape_string($_POST['username']);
$my_password = $mysqli->real_escape_string($_POST['password']);
$my_sql_query = "SELECT * FROM users WHERE username='" . $my_username . "' AND user_password='" . $my_password . "';";
?>

Note : real_escape_string aide mais n’est pas une garantie complète, surtout si la requête est construite dynamiquement autrement.

Utiliser des requêtes paramétrées (recommandé)

Les requêtes paramétrées séparent le code SQL des données. Le moteur reçoit la requête et les paramètres distinctement, empêchant la donnée d’être interprétée comme du code.

Exemples prêts à l’emploi

PHP avec MySQLi (préparé)

prepare('SELECT * FROM users WHERE username = ? AND user_password = ?');
$stmt->bind_param('ss', $_POST['username'], $_POST['password']);
$stmt->execute();
$result = $stmt->get_result();
?>

PHP avec PDO

 PDO::ERRMODE_EXCEPTION]);
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = :username AND user_password = :password');
$stmt->execute(['username' => $_POST['username'], 'password' => $_POST['password']]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

Python avec psycopg2 (PostgreSQL)

import psycopg2
conn = psycopg2.connect(dbname='db', user='user', password='pass')
cur = conn.cursor()
cur.execute('SELECT * FROM users WHERE username = %s AND user_password = %s', (username, password))
rows = cur.fetchall()

Java avec PreparedStatement

PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE username = ? AND user_password = ?");
ps.setString(1, username);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();

Ces exemples montrent la séparation code/données. Privilégiez toujours les APIs de votre pilote qui supportent les paramètres.

Restreindre les permissions

Appliquez le principe du moindre privilège. Le compte que votre application utilise pour se connecter à la base ne doit avoir que les droits nécessaires : SELECT, INSERT, UPDATE, DELETE limités aux tables requises.

Exemple de bonnes pratiques :

  • Créer un compte applicatif distinct pour chaque application.
  • Interdire l’utilisation d’un compte dbadmin pour les opérations applicatives.
  • Révoquer les permissions aux objets systèmes si possible.

Exemple T-SQL simplifié pour refuser certaines sélections :

DENY SELECT ON sys.tables TO sqldatabasepermit;
DENY SELECT ON sys.packages TO sqldatabasepermit;
DENY SELECT ON sys.sysobjects TO sqldatabasepermit;

Masquer les erreurs et journaliser en sécurité

  • Ne renvoyez jamais les messages SQL bruts à l’utilisateur final.
  • Journalisez les erreurs détaillées dans des systèmes sûrs accessibles uniquement aux équipes d’opération.
  • Surveillez les erreurs répétées, tentatives d’injection et requêtes anormales.

Autres mesures de renforcement

  • Utiliser un ORM correctement configuré (attention aux requêtes SQL brutes).
  • Mettre en place un WAF (Web Application Firewall) comme couche supplémentaire.
  • Limiter la surface d’attaque : désactiver procédures inutiles, macros, fonctions externes.
  • Sauvegardes régulières et plan de restauration testé.

Contre-exemples et limites

Les protections ci-dessus réduisent fortement le risque, mais elles ne sont pas infaillibles si :

  • Le serveur applicatif est compromis et peut exécuter des requêtes arbitraires.
  • Du code legacy construit encore des requêtes dynamiques non vérifiées.
  • Des privilèges excessifs existent ailleurs (par ex. maintenance, scripts automatisés qui utilisent des comptes larges).

Rappel : la défense en profondeur est essentielle. Combinez plusieurs mesures.

Snippets et cheat sheet rapide

  • Toujours préférer PreparedStatement/paramètres plutôt que concaténation.
  • Valider côté serveur, jamais uniquement côté client.
  • Journaliser et alerter sur patterns comme ' OR '1'='1 ou utilisation récurrente de commentaires SQL (--, /*).
  • Scanner régulièrement votre code avec outils SAST et exécuter tests d’intrusion.

Extrait minimal PDO sécurisé

$pdo = new PDO(...);
$stmt = $pdo->prepare('INSERT INTO comments (user_id, comment) VALUES (:uid, :c)');
$stmt->execute(['uid' => $userId, 'c' => $comment]);

Diagramme de décision pour suspicion d’injection

flowchart TD
  A[Détection d'une requête suspecte] --> B{La requête utilise des paramètres ?}
  B -- Oui --> C[Examiner logs et alerter]
  B -- Non --> D[Bloquer la requête et capturer payload]
  D --> E[Analyser payload et reproduire en environnement sécurisé]
  E --> F{Injection confirmée ?}
  F -- Oui --> G[Isoler l'application et révoquer clefs]
  F -- Non --> C
  G --> H[Appliquer patch, tests et restaurer]

Playbook d’incident réduit (runbook)

  1. Isoler l’application vulnérable (mettre en maintenance).
  2. Révoquer ou changer les credentials applicatifs.
  3. Capturer logs et payloads pour analyse.
  4. Reproduire localement pour identifier la faille (ex: concaténation, injection dans LIKE, UNION, etc.).
  5. Appliquer correctif (requêtes paramétrées, validation stricte).
  6. Effectuer tests automatisés et manuels (tests d’intrusion ciblés).
  7. Remettre en service et surveiller étroitement.
  8. Communiquer aux parties prenantes selon la politique de sécurité.

Important

  • Ne pas redémarrer ou restaurer la base sans comprendre l’étendue de la compromission.

Checklist par rôle

Développeur

  • Utiliser requêtes paramétrées partout.
  • Valider et assainir toutes les entrées côté serveur.
  • Éviter SQL dynamique quand c’est possible.
  • Écrire tests unitaires pour les cas d’entrée malveillante.

DBA

  • Mettre en place comptes applicatifs limités.
  • Auditer permissions périodiquement.
  • Configurer alertes sur requêtes anormales et volumes inhabituels.

Ingénieur sécurité

  • Exécuter scans SAST réguliers.
  • Planifier tests d’intrusion et revue de code critique.
  • Déployer WAF et règles adaptées.

Cas de test et critères d’acceptation

Tests manuels

  • Envoyer payloads classiques (' OR '1'='1, '; DROP TABLE users; --) et vérifier que la requête n’exécute pas de comportement non prévu.
  • Tester saisies longues, caractères spéciaux, encodages Unicode.

Critères d’acceptation

  • Les entrées malveillantes ne doivent pas modifier la structure des requêtes.
  • Les comptes applicatifs ne doivent pas pouvoir effectuer d’actions hors périmètre.
  • Les logs doivent enregistrer toute tentative d’injection et déclencher une alerte.

Glossaire rapide

  • Injection SQL : exécution non prévue d’instructions SQL fournies via l’entrée.
  • Requête paramétrée : requête SQL où les paramètres sont fournis séparément et non concaténés.
  • WAF : Web Application Firewall, filtre le trafic HTTP.

Faits clés

  • Aucune mesure unique n’offre une protection complète. Combinez validation, paramètres, permissions et surveillance.
  • Les requêtes paramétrées restent la méthode la plus fiable pour bloquer les injections côté application.

Questions fréquentes

Q : Est-ce que l’escape des caractères suffit ?

R : L’escape aide mais n’est pas une garantie. Les prepared statements sont préférables.

Q : Les ORM me protègent-ils automatiquement ?

R : Les ORM offrent souvent une protection par défaut, mais l’utilisation de requêtes brutes ou une mauvaise configuration peut exposer la base.

Q : Dois-je tester la production avec des payloads d’injection ?

R : Non. Testez en environnement isolé de préproduction ou en laboratoire contrôlé. Exécuter des payloads dangereux en production est risqué.

Conclusion

L’injection SQL reste une menace majeure pour les applications utilisant des bases relationnelles. En appliquant une défense en profondeur — validation stricte, requêtes paramétrées, permissions minimales, surveillance et tests — vous réduisez fortement le risque. Utilisez les checklists et le playbook fournis pour structurer votre prévention et votre réponse.

Résumé des actions prioritaires

  • Corriger le code qui concatène des entrées utilisateurs dans des requêtes SQL.
  • Remplacer par des requêtes paramétrées dans tous les points d’entrée.
  • Restreindre les permissions et masquer les erreurs.
  • Mettre en place monitoring, alertes et tests réguliers.
Auteur
Édition

Matériaux similaires

Installer Asterisk pour un PBX (guide débutant)
Téléphonie

Installer Asterisk pour un PBX (guide débutant)

Microsoft Store ne fonctionne pas : dépannage rapide
Support technique

Microsoft Store ne fonctionne pas : dépannage rapide

Sécurité WordPress : scanner et protéger en 10 étapes
Sécurité WordPress

Sécurité WordPress : scanner et protéger en 10 étapes

Flux RSS depuis notifications de forum via Blogger
Tutoriel

Flux RSS depuis notifications de forum via Blogger

Installer OCS Inventory NG Server 2 sur CentOS 5.5
Administration système

Installer OCS Inventory NG Server 2 sur CentOS 5.5

CHAR dans Google Sheets — insérer tous les caractères
Productivité

CHAR dans Google Sheets — insérer tous les caractères