# Prévenir l'injection SQL en PHP

> Prévenir l'injection SQL en PHP : requêtes préparées avec PDO et mysqli, listes blanches pour colonnes, droits minimaux. Exemples et liste de contrôle.

Source : https://phpsos.de/fr/ratgeber/sql-injection-php/  
État : 25/10/2026  
Fournisseur : PHP SOS, Assistance d'urgence PHP et sécurité des serveurs. Aide immédiate par WhatsApp : https://wa.me/491736494914?text=Bonjour%20PHP%20SOS%2C%20nous%20avons%20besoin%20d%27aide%20avec%20notre%20serveur%20PHP.%20Entreprise%20%3A%20%E2%80%A6%20Site%20web%20%3A%20%E2%80%A6

**En bref :** vous prévenez l'injection SQL en PHP de façon fiable en n'intégrant jamais de valeurs dans les textes SQL, mais en les transmettant toujours par des requêtes préparées avec des paramètres. Pour les noms de colonnes et de tables, qui ne peuvent pas être transmis comme paramètres, une liste blanche fixe s'applique. En outre, un utilisateur de base de données aux droits minimaux limite les dégâts si une faille subsiste malgré tout.

## Pourquoi l'injection SQL ne doit pas sortir du champ de vision après PHP2Shell

En octobre 2026, beaucoup de choses tournent autour de PHP2Shell, deux failles critiques de l'interpréteur PHP, corrigées depuis le 21 octobre 2026 dans PHP 8.5.12, 8.4.27, 8.3.36 et 8.2.35. De nombreuses équipes ont mis à jour des serveurs et redémarré des processus ces jours-ci. C'est juste et urgent.

Un état de PHP à jour ne dit toutefois rien de votre propre code. L'injection SQL compte depuis des années parmi les vulnérabilités les plus fréquentes des applications web et figure dans l'OWASP Top 10 sous la catégorie Injection. Qui prévoit de toute façon des contrôles de sécurité devrait examiner du même coup les accès à la base de données de sa propre application.

La bonne nouvelle : l'injection SQL est l'une des rares vulnérabilités que l'on peut presque entièrement exclure avec une règle simple, appliquée avec constance.

## Comment l'injection SQL se produit-elle en PHP ?

L'injection SQL se produit lorsqu'une application traite des saisies d'utilisateur comme une partie d'une commande SQL au lieu de simples données. Typique : assembler une requête à partir de blocs de texte et de variables. Si un visiteur peut déterminer le contenu d'une telle variable, il peut le cas échéant modifier le sens de la commande.

Les conséquences vont de la lecture de données clients d'autrui à la modification de prix ou de droits, jusqu'à la suppression de tables entières. Selon la base de données et les droits, une faille peut aussi permettre des accès au-delà de la base de données. Si des données personnelles sont concernées, une obligation de notification au titre du RGPD peut apparaître.

Les saisies ne sont pas seulement les champs de formulaire. Les paramètres d'URL, les cookies, les en-têtes HTTP, les fichiers téléversés, les réponses d'interfaces tierces et les données déjà enregistrées dans votre propre base de données sont eux aussi considérés comme non fiables.

## Requêtes préparées avec PDO et mysqli

Les requêtes préparées envoient la commande SQL et les valeurs séparément à la base de données. Les valeurs ne sont jamais interprétées comme une partie de la commande. Avec PDO, une requête sûre se présente ainsi :

```php
<?php
$pdo = new PDO($dsn, $benutzer, $passwort, [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES   => false,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

$stmt = $pdo->prepare('SELECT id, name, email FROM kunden WHERE id = :id AND status = :status');
$stmt->execute([
    'id'     => (int) $_GET['id'],
    'status' => 'aktiv',
]);
$kunde = $stmt->fetch();
```

L'option `PDO::ATTR_EMULATE_PREPARES => false` fait en sorte que la base de données utilise de véritables requêtes préparées, pour autant que le pilote le permette. Avec mysqli, le même principe s'applique :

```php
<?php
$stmt = $mysqli->prepare('SELECT id, name FROM produkte WHERE kategorie = ? AND preis <= ?');
$stmt->bind_param('sd', $kategorie, $maxPreis);
$stmt->execute();
$ergebnis = $stmt->get_result();
```

Les listes pour `IN (...)` peuvent aussi être représentées en toute sécurité, en générant un paramètre distinct pour chaque valeur et en transmettant les valeurs séparément.

```php
<?php
$ids = array_map('intval', $ausgewaehlteIds);
$platzhalter = implode(',', array_fill(0, count($ids), '?'));
$stmt = $pdo->prepare("SELECT id, name FROM produkte WHERE id IN ($platzhalter)");
$stmt->execute($ids);
```

## Cas particuliers : noms de colonnes, tri et SQL brut

Les paramètres ne fonctionnent que pour les valeurs, pas pour les noms de tables, les noms de colonnes ou les sens de tri. C'est précisément ici que naissent en pratique de nombreuses failles, par exemple avec des tableaux triables ou des filtres. La solution est une liste fixe de valeurs autorisées :

```php
<?php
$erlaubteSpalten = ['name' => 'name', 'preis' => 'preis', 'datum' => 'erstellt_am'];
$spalte   = $erlaubteSpalten[$_GET['sort'] ?? ''] ?? 'name';
$richtung = (($_GET['dir'] ?? '') === 'desc') ? 'DESC' : 'ASC';

$stmt = $pdo->query("SELECT id, name, preis FROM produkte ORDER BY $spalte $richtung");
```

Les frameworks et les CMS apportent leurs propres outils. Dans WordPress, `$wpdb->prepare()` assume cette tâche ; dans Laravel et Symfony, ce sont les générateurs de requêtes et les ORM. Dès que vous y utilisez du SQL brut, par exemple via des fonctions dont le nom contient « raw », les règles de cette section s'appliquent de nouveau. Des indications sur Laravel figurent sous [Sécuriser les applications Laravel](https://phpsos.de/fr/plattformen/laravel/).

> **Astuce:**
> Recherchez de façon ciblée dans le code les textes SQL dans lesquels des variables sont insérées. Un bon début est une recherche de `query(` et `->raw` en combinaison avec `$_GET`, `$_POST` ou `$_REQUEST`.

## Repérer l'injection SQL dans le code existant

Avec un logiciel neuf, la règle peut être tenue dès le départ. C'est plus difficile avec des applications développées au fil des années. Il vaut alors la peine de rechercher systématiquement les endroits où des textes SQL sont assemblés avec des variables :

```bash
# Commandes SQL dans lesquelles des variables sont insérées
grep -rnE "(SELECT|INSERT|UPDATE|DELETE)[^;]*\\\$[a-zA-Z_]" src/ --include="*.php" | head -50
# Utilisation directe de données de requête dans des fonctions de requête
grep -rnE "(query|exec|raw)\s*\(.*\\\$_(GET|POST|REQUEST|COOKIE)" src/ --include="*.php"
```

Tous les résultats ne sont pas des failles, par exemple lorsque la variable ne contient qu'un nom de table fixe. Chaque occurrence devrait toutefois être examinée consciemment une fois et, au besoin, convertie en requêtes préparées. Des outils d'analyse statique du code aident à repérer durablement de tels motifs dans le pipeline de build, de sorte que les nouvelles erreurs ne passent même pas en production.

## Limiter les dégâts : droits, messages d'erreur, contrôle

Un code sûr est la première ligne de défense. D'autres niveaux limitent les dégâts si une faille est tout de même négligée :

- **Droits minimaux :** l'utilisateur de base de données du site n'a en général besoin que de `SELECT`, `INSERT`, `UPDATE` et `DELETE` sur sa propre base, sans droit de créer des utilisateurs ni d'accéder à d'autres bases de données.
- **Aucun message d'erreur vers l'extérieur :** `display_errors = Off` dans php.ini. Les erreurs de base de données vont dans le journal, pas dans le navigateur.
- **Séparation par application :** chaque site obtient son propre utilisateur de base de données.
- **Garder les dépendances à jour :** des failles se trouvent aussi dans les bibliothèques, comme le montre le guide [composer audit](https://phpsos.de/fr/ratgeber/composer-abhaengigkeiten-pruefen/).
- **Faire contrôler :** la revue de code et l'analyse automatisée trouvent de nombreux endroits ; un test d'intrusion montre ce qui est réellement accessible de l'extérieur.

```sql
-- Exemple : utilisateur de base de données avec seulement les droits nécessaires
CREATE USER 'shop_app'@'localhost' IDENTIFIED BY '<starkes Passwort>';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'shop_app'@'localhost';
```

Une vulnérabilité voisine concerne l'affichage des données dans le navigateur. Le guide [Prévenir le cross-site scripting en PHP](https://phpsos.de/fr/ratgeber/xss-php/) explique comment la sécuriser.

## Comment PHP SOS aide-t-il concrètement ?

- Nous examinons systématiquement les accès à la base de données de votre application à la recherche de requêtes non sûres.
- Nous hiérarchisons les constats selon l'accessibilité et les données concernées et montrons des corrections concrètes.
- Nous amenons les droits de la base de données et la gestion des erreurs à un niveau sûr.
- Nous retestons après la correction et documentons le résultat.

La prestation [Audit de sécurité et test d'intrusion](https://phpsos.de/fr/leistungen/sicherheitsaudit-penetrationstest/) décrit un contrôle indépendant.


## Questions fréquentes

**Suffit-il de traiter les entrées avec addslashes ou real_escape_string ?**  
Non, c'est sujet aux erreurs. L'échappement dépend du jeu de caractères et du contexte et est facilement oublié à un endroit. Les requêtes préparées séparent par principe la commande et les données ; c'est pourquoi elles constituent la voie recommandée.

**Un ORM protège-t-il automatiquement de l'injection SQL ?**  
Dans une large mesure, tant que vous utilisez les fonctions de requête de l'ORM. Dès que vous écrivez du SQL brut ou insérez des valeurs dans des tris et des noms de colonnes, les mêmes règles s'appliquent que sans ORM.

**Un pare-feu applicatif web aide-t-il contre l'injection SQL ?**  
Un WAF peut intercepter des motifs connus et faire gagner du temps. Il ne remplace toutefois pas un code sûr, car des règles fondées sur les données de la requête peuvent être contournées et touchent parfois des entrées légitimes.

**La mise à jour de PHP contre PHP2Shell comble-t-elle aussi les failles d'injection SQL ?**  
Non. PHP2Shell concerne l'interpréteur PHP. L'injection SQL est une erreur dans le code applicatif et subsiste quelle que soit la version de PHP qui tourne.

## Sources

- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
- [php.net : avis de sécurité](https://www.php.net/)
