PDO en PHP : protège-t-il à 100% contre les injections SQL ?

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 : Mythes et réalité de PDO

\n\n

Si vous programmez en PHP et avez déjà cherché « comment se protéger des injections SQL », vous avez sûrement entendu le mantra : « Utilisez PDO et les requêtes préparées – et vous serez heureux ». C'est la référence absolue, la base de tout manuel de sécurité PHP. Mais est-ce vraiment le cas ? Suffit-il d'écrire $stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?') et d'oublier le problème ?

\n\n

La question « Les requêtes préparées PDO sont-elles suffisantes pour prévenir les injections SQL ? » a accumulé des milliers de vues sur Stack Overflow pour une bonne raison. La réponse, comme il s'avère, n'est pas si évidente. Dans cet article, nous allons explorer sous le capot de PDO, comprendre comment fonctionnent réellement les requêtes préparées, et découvrir dans quels cas même PDO peut vous trahir.

\n\n

Ce n'est pas de la théorie ennuyeuse. Nous examinerons des exemples concrets, l'émulation de requêtes, les subtilités des encodages et donnerons des actions concrètes pour que votre code soit véritablement protégé.

\n\n

Comment fonctionnent les requêtes préparées : Magie ou mathématiques ?

\n\n

Pour commencer, rappelons ce qu'est une injection SQL. C'est lorsqu'un attaquant transmet dans une requête des données qui sont interprétées comme faisant partie du code SQL. Le classique : ' OR 1=1 --.

\n\n

Les requêtes préparées résolvent ce problème de manière radicale. Elles séparent la logique de la requête et les données. Cela ressemble à ceci :

\n\n
<?php\n$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');\n$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status = :status');\n$stmt->execute([':email' => $_GET['email'], ':status' => 'active']);\n?>\n
\n\n

Sous le capot, voici ce qui se passe :

\n\n
    \n
  1. Préparation : Le pilote envoie au serveur de base de données le « squelette » de la requête : SELECT * FROM users WHERE email = ? AND status = ?. Le serveur analyse ce squelette, l'optimise et mémorise le plan d'exécution. La place pour les données (les paramètres fictifs) reste vide pour l'instant.
  2. \n
  3. Exécution : Vous envoyez maintenant uniquement les valeurs réelles. Le serveur les insère dans le plan déjà prêt, mais il le fait d'une manière particulière – il sait que ce sont des données, pas du code. Ainsi, toute tentative de « fermer le guillemet » ou d'ajouter une commande SQL se transforme simplement en partie du littéral de chaîne.
  4. \n
\n\n

Cela semble idéal. Mais il y a un hic.

\n\n

Le piège : L'émulation des requêtes préparées

\n\n

La principale surprise révélée par cette fameuse question sur Stack Overflow : PDO n'utilise pas toujours par défaut de « vraies » requêtes préparées.

\n\n

En effet, toutes les bases de données ne supportent pas cette fonctionnalité au niveau du protocole. Et certains pilotes (par exemple, pour SQLite ou les anciennes versions de MySQL) fonctionnent via une émulation. Qu'est-ce que cela signifie ?

\n\n

Lorsque l'émulation est activée, PDO insère lui-même les valeurs dans la requête SQL côté client (en PHP), puis envoie la requête déjà complète au serveur. Ce faisant, il échappe les caractères spéciaux avec PDO::quote().

\n\n

Et c'est là que les problèmes commencent. L'émulation est, en substance, la même substitution de chaînes, mais effectuée par la bibliothèque. Et si vous avez mal défini l'encodage de la connexion, ce mécanisme peut être contourné.

\n\n

Exemple : Attaque via différents encodages

\n\n

L'attaque classique utilisant un encodage incorrect se présente ainsi. Supposons que vous ayez établi une connexion à MySQL avec l'encodage GBK (un encodage chinois), et que la requête elle-même soit émulée. Le caractère \\ (antislash) en GBK peut faire partie d'un caractère multi-octets.

\n\n

L'attaquant transmet la chaîne : %BF%27. Dans l'encodage GBK, la séquence %BF%5C forme un seul caractère, tandis que %27 est simplement un guillemet. L'émulateur voit le guillemet et l'échappe, transformant %27 en %5C%27 (c'est-à-dire \\'). Mais parce que le

Blogs

Book Recommendations