PDO et faille de sécurité - david-alpha/gdn GitHub Wiki

💥 Sécurité en PHP avec PDO : Exemples de Faille et de Code Sécurisé

Ce projet démontre une faille d'injection SQL via PDO mal utilisé en PHP, et propose une version sécurisée utilisant les requêtes préparées.


📁 Contenu des fichiers

  • insecure.php : version vulnérable à l'injection SQL
  • secure.php : version sécurisée avec prepare() et execute()
  • init.sql : script SQL pour créer une base de test avec une table users
  • README.md : documentation

⚠️ 1. Fichier vulnérable : insecure.php

<?php
// Connexion PDO (vulnérable)
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'root', '');

// Récupère les données de l'utilisateur via GET
$username = $_GET['username'];

// ⚠️ Requête vulnérable à l'injection SQL
$sql = "SELECT * FROM users WHERE username = '$username'";
$stmt = $pdo->query($sql);

echo "<h2>Résultat :</h2>";
foreach ($stmt as $row) {
    echo "Nom d'utilisateur : " . htmlspecialchars($row['username']) . "<br>";
}
?>

🔓 Exemple d'injection SQL

URL utilisée :

http://localhost:8000/insecure.php?username=' OR '1'='1

Cela permet de contourner la logique de sécurité et d'afficher tous les utilisateurs de la table.


✅ 2. Fichier sécurisé : secure.php

<?php
// Connexion PDO sécurisée
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'root', '');

// Requête préparée sécurisée
$username = $_GET['username'] ?? '';

$sql = "SELECT * FROM users WHERE username = :username";
$stmt = $pdo->prepare($sql);
$stmt->execute(['username' => $username]);

echo "<h2>Résultat :</h2>";
foreach ($stmt as $row) {
    echo "Nom d'utilisateur : " . htmlspecialchars($row['username']) . "<br>";
}
?>

✅ Avantages de cette version

  • Paramètres liés via prepare() et execute() : empêche les injections SQL
  • Plus lisible, plus sûr, recommandé en production

🛠 3. Script SQL : init.sql

CREATE DATABASE IF NOT EXISTS testdb;
USE testdb;

CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL
);

INSERT INTO users (username) VALUES
('alice'),
('bob'),
('charlie');

🔐 Bonnes pratiques générales

  • Toujours utiliser des requêtes préparées (prepare() + execute())
  • Ne jamais interpoler directement les variables dans les requêtes SQL
  • Échapper les affichages avec htmlspecialchars()
  • Ne pas afficher les erreurs PDO en production
  • Restreindre les droits MySQL : pas d’admin pour une simple lecture
  • Activer le mode d’exception PDO :
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

🧪 Test complet

Étape 1 : Importer la base de données

mysql -u root -p < init.sql

Étape 2 : Lancer un serveur local PHP

php -S localhost:8000

Étape 3 : Tester dans votre navigateur


👨‍💻 Auteur

Ce projet a été conçu à titre pédagogique pour illustrer les failles courantes dans les applications web PHP/MySQL.

⚠️ **GitHub.com Fallback** ⚠️