En bref, voici ce qu'il faut savoir
- Une injection SQL exploite des champs de formulaire non sécurisés pour exécuter du code malveillant dans une base de données.
- L’extension mysql en PHP, aujourd’hui obsolète, n’autorisait pas les requêtes préparées et exposait fortement aux attaques par injection.
- Les requêtes préparées avec PDO isolent la structure SQL des données entrées, empêchant l’exécution de code via des marqueurs comme? ou:email.
- La validation côté serveur des entrées, comme vérifier un email avec filter_var, est une étape cruciale avant tout traitement en base.
Un tiers des failles de sécurité web découle encore d’une mauvaise gestion des entrées utilisateurs, une vulnérabilité souvent transmise par héritage entre développeurs. Ce constat n’a rien de neuf, et pourtant, les injections SQL restent une porte ouverte pour les attaquants. Derrière un simple champ de formulaire peut se cacher une faille critique. Heureusement, les bonnes pratiques existent - et elles sont accessibles à tous. Décryptage d’une menace persistante et des moyens simples de s’en prémunir.
Les fondamentaux de la protection contre les injections SQL
Comprendre le mécanisme de l'attaque
Une injection SQL consiste à insérer du code malveillant dans un champ de formulaire pour manipuler une requête de base de données. Par exemple, un attaquant peut saisir une chaîne comme ' OR '1'='1 dans un champ de connexion. Si le site n’assainit pas correctement les entrées, cette saisie peut contourner l’authentification en modifiant la logique de la requête SQL.
Le danger ne se limite pas à l’accès non autorisé. Une injection malveillante peut permettre d’extraire, de modifier ou même de supprimer des données sensibles. Dans les cas extrêmes, un pirate peut prendre le contrôle total du serveur. La faille réside souvent dans le fait de concaténer directement des variables utilisateur dans une requête SQL, sans aucune validation.
La règle d'or: ne jamais faire confiance à l'utilisateur
Qu’il s’agisse d’un visiteur légitime ou d’un attaquant, toute donnée venant de l’utilisateur doit être traitée comme potentiellement dangereuse. Cela inclut les données envoyées via _POST, _GET, ou même les en-têtes HTTP. La première ligne de défense est donc la sanitisation des entrées.
Cela signifie filtrer, valider et éventuellement échapper toute information avant de l’utiliser dans une requête. Par exemple, si un champ attend un nombre, on doit s’assurer qu’il s’agit bien d’un entier. Même une erreur innocente de la part d’un utilisateur peut révéler une faille. Le principe est simple: ne jamais faire confiance à l’utilisateur, quelle que soit sa bonne foi.
Comparatif des méthodes de connexion et sécurité
L'évolution des extensions PHP
À ses débuts, PHP utilisait l’extension mysql, aujourd’hui obsolète et déconseillée. Elle ne supportait pas les requêtes préparées et était vulnérable aux injections. Elle a été remplacée par MySQLi (MySQL Improved), qui permet une meilleure gestion de la sécurité, notamment via les requêtes préparées.
Plus récemment, PDO (PHP Data Objects) s’est imposé comme une solution plus flexible. Il supporte plusieurs types de bases de données (MySQL, PostgreSQL, SQLite, etc.) et favorise une architecture plus propre. Son adoption est fortement recommandée pour tout nouveau projet, notamment pour sa compatibilité avec les bonnes pratiques modernes.
Gestion des erreurs et logs
En production, afficher les erreurs SQL directement à l’utilisateur est une mauvaise idée. Ces messages peuvent révéler la structure de la base de données, les noms de tables ou les requêtes utilisées - autant d’indices pour un pirate. La bonne pratique consiste à désactiver l’affichage des erreurs et à les rediriger vers des fichiers de log sécurisés.
Un système de journalisation permet de surveiller les tentatives anormales sans exposer d’informations sensibles. Attraper les exceptions via des blocs try/catch permet de gérer les erreurs silencieusement tout en conservant un contrôle total sur le comportement de l’application.
| Extension | Sécurité | Flexibilité | Facilité d'usage |
|---|---|---|---|
| MySQL (obsolète) | Faible | Faible | Simple, mais risquée |
| MySQLi (procédural) | Moyenne à bonne | Modérée | Technique, nécessite vigilance |
| MySQLi (orienté objet) | Bonne | Modérée | Clair, structuré |
| PDO | Excellente | Élevée (multi-SGBD) | Élégante, moderne |
Implémenter les requêtes préparées avec PDO
Séparer le code SQL des données
La méthode la plus efficace pour prévenir les injections SQL est l’utilisation de requêtes préparées. Le principe est simple: on sépare la structure de la requête SQL de ses données. Grâce aux marqueurs (placeholders), comme :email ou ?, la base de données prépare la requête sans y intégrer les valeurs utilisateur.
Lors de l’exécution, les données sont transmises séparément, ce qui empêche toute interprétation malveillante. Même si un attaquant tente d’injecter du code SQL, il sera traité comme une donnée brute, pas comme une instruction. C’est une barrière solide et simple à mettre en œuvre.
Exemple de code sécurisé
Voici un exemple concret avec PDO:
pdo = new PDO(dsn, user, pass);
stmt = pdo->prepare("SELECT * FROM utilisateurs WHERE email =:email");
stmt->bindValue(':email', _POST['email']);
stmt->execute();
Les étapes sont claires: préparation de la requête, liaison des paramètres via bindValue(), puis exécution. Ce schéma devient vite un automatisme, et il protège efficacement contre les tentatives d’injection. Le code reste propre, lisible et sécurisé.
Checklist pour un formulaire totalement hermétique
Nettoyage et validation des types
Avant même d’atteindre la base de données, les données doivent être validées côté serveur. Un champ d’email doit être vérifié avec filter_var(_POST['email'], FILTER_VALIDATE_EMAIL). Un champ numérique doit être casté ou validé avec is_numeric(). Cette étape simple mais cruciale évite bien des désagréments.
La sanitisation des entrées ne remplace pas la validation, mais la complète. Elle permet d’éliminer les caractères indésirables, sans pour autant garantir la sécurité face à une injection SQL - d’où l’importance de combiner cette étape avec les requêtes préparées.
Mesures complémentaires indispensables
La sécurité ne s’arrête pas à la requête SQL. D’autres bonnes pratiques renforcent la protection globale:
- Utiliser un compte base de données avec les privilèges minimums nécessaires
- Mettre à jour régulièrement PHP, le SGBD et les dépendances
- Désactiver les messages d’erreur détaillés en production
- Appliquer la sanitisation des sorties pour éviter les XSS
La sécurité est un processus continu, pas une configuration unique. Un formulaire bien conçu aujourd’hui peut devenir une faille demain sans maintenance.
Les questions posées régulièrement
Est-ce que l'utilisation de addslashes() suffit à protéger mon site?
Non, cette méthode est obsolète et insuffisante. Elle ne protège pas contre toutes les formes d’injection et peut être contournée par des attaquants expérimentés. Elle ne remplace en aucun cas l’utilisation de requêtes préparées, qui restent la solution la plus fiable.
Vaut-il mieux utiliser PDO ou MySQLi pour débuter un projet?
PDO est généralement préféré pour sa portabilité et sa syntaxe élégante. Il permet de changer de SGBD sans réécrire l’ensemble des requêtes. MySQLi est performant mais plus spécifique à MySQL. Pour un nouveau projet, PDO est souvent le meilleur choix.
Par quoi dois-je commencer pour sécuriser un site déjà en ligne?
Commencez par auditer les formulaires critiques: connexion, inscription, contact. Vérifiez l’usage des requêtes préparées et la validation des entrées. Mettez à jour les composants obsolètes. Un audit ciblé permet de corriger les failles les plus urgentes rapidement.