Lorsqu'il s'agit de requêtes de base de données, essayez toujours d'utiliser des requêtes paramétrées préparées. Le site mysqli
y PDO
les bibliothèques soutiennent cela. C'est infiniment plus sûr que d'utiliser des fonctions d'échappement telles que mysql_real_escape_string
.
Sí, mysql_real_escape_string
est en fait une simple fonction d'échappement des chaînes de caractères. Il ne s'agit pas d'une solution miracle. Tout ce qu'elle fait, c'est échapper les caractères dangereux afin qu'ils puissent être utilisés en toute sécurité dans une seule chaîne de requête. Toutefois, si vous n'aseptisez pas vos entrées au préalable, vous serez vulnérable à certains vecteurs d'attaque.
Imaginez le SQL suivant :
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
Vous devriez être en mesure de voir que cela est vulnérable à l'exploitation.
Imaginez la id
contenait le vecteur d'attaque commun :
1 OR 1=1
Il n'y a pas de caractères à risque à encoder, donc il passera directement à travers le filtre d'échappement. Ce qui nous laisse :
SELECT fields FROM table WHERE id= 1 OR 1=1
Ce qui est un joli vecteur d'injection SQL et permettrait à l'attaquant de retourner toutes les lignes. Ou
1 or is_admin=1 order by id limit 1
qui produit
SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
Ce qui permet à l'attaquant de renvoyer les détails du premier administrateur dans cet exemple totalement fictif.
Bien que ces fonctions soient utiles, elles doivent être utilisées avec précaution. Vous devez vous assurer que toutes les entrées web sont validées dans une certaine mesure. Dans ce cas, nous voyons que nous pouvons être exploités parce que nous n'avons pas vérifié qu'une variable que nous utilisions comme un nombre, était réellement numérique. En PHP, vous devriez largement utiliser un ensemble de fonctions pour vérifier que les entrées sont des entiers, des flottants, des alphanumériques, etc. Mais lorsqu'il s'agit de SQL, il faut surtout tenir compte de la valeur de l'instruction préparée. Le code ci-dessus aurait été sécurisé s'il s'agissait d'une instruction préparée car les fonctions de la base de données auraient su que 1 OR 1=1
n'est pas un littéral valide.
Quant à htmlspecialchars()
. C'est un champ de mines en soi.
Il y a un vrai problème en PHP, car il y a toute une sélection de différentes fonctions d'échappement liées au html, et il n'y a pas d'indications claires sur ce que font exactement ces fonctions.
Tout d'abord, si vous êtes à l'intérieur d'une balise HTML, vous avez de gros problèmes. Regardez
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
Nous sommes déjà à l'intérieur d'une balise HTML, donc nous n'avons pas besoin de < ou > pour faire quoi que ce soit de dangereux. Notre vecteur d'attaque pourrait simplement être javascript:alert(document.cookie)
Maintenant le HTML résultant ressemble à
<img src= "javascript:alert(document.cookie)" />
L'attaque passe directement à travers.
C'est pire. Pourquoi ? Parce que htmlspecialchars
(lorsqu'il est appelé de cette façon) ne code que les guillemets doubles et non les simples. Ainsi, si nous avions
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
Notre attaquant maléfique peut maintenant injecter de tout nouveaux paramètres
pic.png' onclick='location.href=xxx' onmouseover='...
nous donne
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
Dans ces cas, il n'y a pas de solution miracle, il faut simplement sanctifier soi-même l'entrée. Si vous essayez de filtrer les mauvais caractères, vous échouerez à coup sûr. Adoptez une approche de liste blanche et ne laissez passer que les caractères qui sont bons. Regardez les Aide-mémoire sur les XSS pour des exemples de la diversité des vecteurs
Même si vous utilisez htmlspecialchars($string)
en dehors des balises HTML, vous êtes toujours vulnérable aux vecteurs d'attaque par jeu de caractères multi-octets.
Le plus efficace est d'utiliser une combinaison de mb_convert_encoding et htmlentities comme suit.
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
Même cela laisse IE6 vulnérable, en raison de la façon dont il gère les UTF. Cependant, vous pouvez vous rabattre sur un encodage plus limité, tel que ISO-8859-1, jusqu'à ce que l'utilisation d'IE6 diminue.
Pour une étude plus approfondie des problèmes de multi-octets, voir https://stackoverflow.com/a/12118602/1820