Injection SQL contournant mysql_real_escape_string() : analyse des vulnérabilités

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

« Au secours ! Ma mysql_real_escape_string() ne fonctionne pas ! »



Si vous avez déjà cherché sur Google « SQL injection that gets around mysql_real_escape_string() », vous n'êtes pas seul. Cette question sur Stack Overflow a cumulé des dizaines de milliers de vues et est devenue un classique de la sécurité web. On pourrait penser qu'en utilisant mysql_real_escape_string(), on est protégé. Mais non. Les hackers trouvent des failles, et les développeurs, des cheveux blancs.



Dans cet article, nous allons analyser comment les injections SQL peuvent contourner l'échappement de mysql_real_escape_string() en PHP. Vous verrez des exemples de code réels, comprendrez pourquoi l'« ancienne bonne » approche ne fonctionne plus, et apprendrez comment vous protéger efficacement. C'est parti !



Pourquoi mysql_real_escape_string() n'est pas une panacée ?



Pour commencer, un peu d'histoire. La fonction mysql_real_escape_string() est apparue à l'époque de PHP 4 et 5, lorsque tout le monde utilisait l'extension mysql_*. Elle échappe les caractères spéciaux comme les guillemets, les antislashs et les caractères de contrôle. Mais le problème est qu'elle ne fonctionne que dans le contexte d'un seul encodage.



Si l'encodage du client et du serveur ne correspondent pas, l'enfer commence. Et si vous utilisez des encodages multi-octets (par exemple, GBK ou SJIS), la fonction peut devenir votre pire ennemi.



Exemple classique : l'attaque multi-octets



Imaginez que votre site utilise l'encodage GBK (chinois) et que vous transmettez la chaîne :



$_POST['name'] = "0xbf27"; // ' échappé ou simplement ' ?


En GBK, le caractère 0xbf27 est un caractère chinois valide. Mais si mysql_real_escape_string() « voit » 0x27 (apostrophe), elle l'échappe avec un antislash : 0xbf5c27. Le problème est que 0xbf5c est aussi un caractère valide en GBK ! Résultat : l'apostrophe 0x27 reste non échappée, et le hacker peut insérer son code SQL.



// Code vulnérable$name = mysql_real_escape_string($_POST['name']);$query = "SELECT * FROM users WHERE name = '$name'";

// Si on saisit : 0xbf27// La fonction retourne : 0xbf5c27// En GBK, cela donne : caractère chinois + apostrophe// La requête devient : SELECT * FROM users WHERE name = 'caractère_chinois' OR 1=1 -- '


Et voilà ! L'injection a réussi. Et ce n'est pas de la théorie — de telles vulnérabilités ont été trouvées dans des projets réels.



Vulnérabilités typiques lors de l'utilisation de mysql_real_escape_string()



Listons les erreurs les plus courantes qui permettent de contourner l'échappement :



  • Mauvais encodage — comme dans l'exemple ci-dessus. Si le serveur pense que les données sont en UTF-8, mais que le client envoie du GBK, l'échappement est cassé.
  • Utilisation de champs numériques sans guillemets — si vous insérez un nombre directement, l'échappement ne fonctionne pas. Exemple : SELECT * FROM users WHERE id = $id — et le hacker écrit 1 OR 1=1.
  • Requêtes LIKE — l'échappement ne traite pas les caractères % et _. Une injection SQL aveugle est possible via des motifs.
  • Échappement multiple — si vous appelez la fonction deux fois, l'antislash est doublé, et la protection disparaît.


Exemple : attaque sur un champ numérique



// Code vulnérable$id = mysql_real_escape_string($_GET['id']);$query = "SELECT * FROM products WHERE id = $id"; // Pas besoin de guillemets !

// Le hacker saisit : 1 UNION SELECT username, password FROM users// La requête devient : SELECT * FROM products WHERE id = 1 UNION SELECT username, password FROM users


L'échappement est ici inutile — il n'y a pas de guillemets à échapper. Le hacker insère directement son SQL.



Méthodes de protection modernes (qui fonctionnent)



Assez d'histoires effrayantes — passons aux solutions. Si vous codez en PHP et voulez oublier les injections SQL, voici votre check-list :



1. Utilisez PDO ou MySQLi avec les requêtes préparées



C'est

Blogs

Book Recommendations