SQL - Injection

Si vous prenez une entrée utilisateur via une page Web et l'insérez dans une base de données SQL, il est possible que vous vous soyez laissé ouvert à un problème de sécurité connu sous le nom de SQL Injection. Ce chapitre vous apprendra comment éviter que cela ne se produise et vous aidera à sécuriser vos scripts et instructions SQL dans vos scripts côté serveur comme un script PERL.

L'injection se produit généralement lorsque vous demandez à un utilisateur une entrée, comme son nom et au lieu d'un nom, il vous donne une instruction SQL que vous exécuterez sans le savoir sur votre base de données. Ne faites jamais confiance aux données fournies par l'utilisateur, ne traitez ces données qu'après validation; en règle générale, cela se fait parPattern Matching.

Dans l'exemple ci-dessous, le name est limité aux caractères alphanumériques plus le trait de soulignement et à une longueur comprise entre 8 et 20 caractères (modifiez ces règles si nécessaire).

if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) {
   $result = mysql_query("SELECT * FROM CUSTOMERS 
      WHERE name = $matches[0]");
} else {
   echo "user name not accepted";
}

Pour démontrer le problème, considérez cet extrait -

// supposed input
$name = "Qadir'; DELETE FROM CUSTOMERS;";
mysql_query("SELECT * FROM CUSTOMSRS WHERE name='{$name}'");

L'appel de fonction est censé récupérer un enregistrement de la table CUSTOMERS où la colonne name correspond au nom spécifié par l'utilisateur. Dans des circonstances normales,$namene contiendrait que des caractères alphanumériques et peut-être des espaces, comme la chaîne ilia. Mais ici, en ajoutant une toute nouvelle requête à $ name, l'appel à la base de données tourne au désastre; la requête DELETE injectée supprime tous les enregistrements de la table CUSTOMERS.

Heureusement, si vous utilisez MySQL, le mysql_query()ne permet pas l'empilement de requêtes ou l'exécution de plusieurs requêtes SQL en un seul appel de fonction. Si vous essayez d'empiler des requêtes, l'appel échoue.

Cependant, d'autres extensions de base de données PHP, telles que SQLite et PostgreSQL exécutez avec plaisir des requêtes empilées, exécutant toutes les requêtes fournies dans une chaîne et créant un problème de sécurité sérieux.

Empêcher l'injection SQL

Vous pouvez gérer tous les caractères d'échappement intelligemment dans des langages de script comme PERL et PHP. L'extension MySQL pour PHP fournit la fonctionmysql_real_escape_string() pour échapper les caractères d'entrée spécifiques à MySQL.

if (get_magic_quotes_gpc()) {
   $name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM CUSTOMERS WHERE name='{$name}'");

Le LIKE Quandary

Pour résoudre le problème LIKE, un mécanisme d'échappement personnalisé doit convertir les caractères '%' et '_' fournis par l'utilisateur en littéraux. Utilisationaddcslashes(), une fonction qui vous permet de spécifier une plage de caractères à échapper.

$sub = addcslashes(mysql_real_escape_string("%str"), "%_");
// $sub == \%str\_
mysql_query("SELECT * FROM messages 
   WHERE subject LIKE '{$sub}%'");