Injections SQL en PHP : comment s'en protéger en 2025

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : pourquoi les injections SQL sont-elles toujours d'actualité ?

\n\n

Imaginez : votre site fonctionne parfaitement, les utilisateurs s'inscrivent, laissent des commentaires, passent des commandes. Et soudain, votre base de données tombe entre les mains d'un attaquant. Non pas parce que les hackers sont des génies, mais parce que quelqu'un a oublié de mettre un point d'interrogation dans une requête SQL.

\n\n

Les injections SQL ne sont pas une menace archaïque des années 2000. En 2024, l'OWASP les classe toujours parmi les trois vulnérabilités les plus dangereuses des applications web. Et la question "How can I prevent SQL injection in PHP?" sur Stack Overflow a dépassé 1,5 million de vues — et continue d'augmenter. Preuve que le problème est bien vivant.

\n\n

Dans cet article, nous allons voir comment verrouiller définitivement la porte aux injections SQL en PHP en 2025. Sans magie, sans frameworks complexes, uniquement du code propre et des bonnes pratiques.

\n\n

Qu'est-ce qu'une injection SQL en termes simples ?

\n\n

Une injection SQL se produit lorsque la saisie utilisateur devient une partie de la commande SQL, et non de simples données. Exemple concret :

\n\n
<?php\n// MAUVAIS CODE — ne faites jamais cela !\n$username = $_POST['username'];\n$query = "SELECT * FROM users WHERE username = '$username'";\n$result = mysqli_query($conn, $query);\n?>
\n\n

Si un attaquant saisit dans le champ username la chaîne ' OR '1'='1, la requête devient :

\n\n
SELECT * FROM users WHERE username = '' OR '1'='1'
\n\n

Cela renvoie tous les utilisateurs. Et si l'on saisit '; DROP TABLE users; --, toute la table peut être supprimée. Flippant, non ?

\n\n

Bonnes pratiques pour se protéger des injections SQL en PHP en 2025

\n\n

1. Utilisez PDO avec des requêtes préparées (c'est la norme)

\n\n

PDO (PHP Data Objects) est une interface universelle pour travailler avec les bases de données. Son principal avantage : il sépare la logique SQL des données. Vous écrivez une requête avec des placeholders, et PDO se charge de l'échappement sécurisé.

\n\n
<?php\n// BON CODE — utilisez PDO\n$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';\n$pdo = new PDO($dsn, $user, $pass, [\n    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,\n    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,\n    PDO::ATTR_EMULATE_PREPARES => false, // désactive l'émulation\n]);\n\n$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');\n$stmt->execute(['email' => $_POST['email']]);\n$user = $stmt->fetch();\n?>
\n\n

Pourquoi ça marche ? La base de données reçoit la structure de la requête séparément des données. Même si l'utilisateur saisit du SQL malveillant, il sera interprété comme une simple chaîne de caractères, et non comme une partie de la commande.

\n\n

2. Mysqli avec des requêtes préparées (alternative)

\n\n

Si vous travaillez uniquement avec MySQL, vous pouvez utiliser mysqli — mais uniquement avec des requêtes préparées, et non avec l'échappement via mysqli_real_escape_string().

\n\n
<?php\n$mysqli = new mysqli('localhost', 'user', 'pass', 'testdb');\n$stmt = $mysqli->prepare('INSERT INTO comments (user_id, text) VALUES (?, ?)');\n$stmt->bind_param('is', $userId, $commentText);\n$stmt->execute();\n?>
\n\n

Important : en 2025, mysqli_real_escape_string() existe toujours, mais compter dessus pour la sécurité est une mauvaise idée. Il échappe uniquement les chaînes, mais ne protège pas contre les injections dans les champs numériques ou les opérateurs LIKE.

\n\n

3. Filtrage et validation — deuxième ligne de défense

\n\n

Les requêtes préparées sont la base. Mais ajoutez-y un filtrage par type de données. Si un nombre est attendu, vérifiez que c'est bien un nombre. Si un email est attendu, vérifiez le format.

\n\n
<?php\n$id = filter_input(INPUT_POST, 'user_id', FILTER_VALIDATE_INT);\nif ($id === false) {\n    throw new InvalidArgumentException('L\\'ID doit être un entier');\n}\n\n$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');\n$stmt->execute(['id' => $id]);\n?>
\n\n

Combiner

Blogs

Book Recommendations