Failles XSS : Comprendre et s'en protéger !

Comprendre ce que sont les failles XSS est quelque chose de crucial lorsque l'on souhaite créer un site web sécurisé.
L'exploitation de ce type de faille par un attaquant peut en effet être dévastateur pour vous et vos utilisateurs.
Qu'est-ce que sont les failles XSS ? Comment s'en protéger ? C'est ce que nous allons essayer de comprendre dans cet article !
 


Qu'est-ce que XSS ?


XSS (Cross-site Scripting) est une faille qui permet à un attaquant d'injecter un script malveillant sur une page web chargée par un client. L'attaquant peut alors avoir la mainmise sur le navigateur et exécuter du code compris par ce dernier.
Le champ des possibles est large tant la faille est critique, cela peut aller de la simple redirection vers un site de phishing comme du vol de cookies sur la page ciblée.
Il existe ainsi plusieurs types de failles XSS que nous allons décrire dans cet article.



 

Failles XSS reflétées (Reflected XSS)


Description

 

Une faille XSS est dite reflétée ou non persistante lorsqu'un attaquant parvient à injecter un script malveillant sur le rendu d'une page web en se servant des valeurs envoyées au serveur depuis la charge utile (payload) d'une requête HTTP. Une façon commune de manipuler un serveur pour effectuer ce type d'attaque est d'envoyer ces valeurs depuis les paramètres d'une URL.
Si le serveur traite des valeurs depuis la charge utile d'une requête HTTP et les intègre au rendu d'une page web sans les avoir sécurisées au préalable, ces valeurs pourraient être parsées comme des objets DOM indésirables dans le navigateur du client. 
La faille XSS reflétée n'est effective que le temps de la requête/réponse d'une requête HTTP spécifique et le script malveillant est en transit seulement de façon "temporaire", par opposition à la faille XSS stockée que nous verrons dans la prochaine section.

Comprendre ce type de faille seulement par du texte peut être compliqué au premier abord, imageons un peu tout ça avec un exemple concret ! 👍


Exemple
 

Prenons l'exemple d'un site web qui met à disposition une banque d'images de petits chiots : 
➡️ cutes-puppies.com 🐶 (Bon en réalité ce sera un localhost, c'est pour l'exemple!)

Une barre de recherche est disponible pour parcourir cette immense banque d'images.
Voyons ce qui se passe lorsqu'un utilisateur soumet "Shiba" dans la barre de recherche :
 

Capture d'écran du site qui sert d'exemple pour la faille XSS reflétée.


La valeur de recherche correspond au paramètre search de l'URL, et sera traité côté serveur pour être réaffichée juste en dessous de la barre de recherche.
Maintenant essayons autre chose. Rentrons <script>alert('Hello World!')</script> dans cette même barre de recherche et voyons ce qu'il se passe à l'envoi.



Capture d'écran d'une tentative d'exploitation de faille XSS reflétée.


Capture d'écran d'une tentative d'exploitation de faille XSS reflétée réussie.

 

Une boîte d'alerte avec le message "Hello World!" s'est affiché ! Que s'est-il passé ?
C'est simple. Le serveur a reçu la valeur <script>alert('Hello World!')</script> dans le paramètre "search" de la requête, et l'a imprimé sans l'encoder dans le rendu / code source de la page. Une fois la page arrivé chez vous, votre navigateur a simplement parsé le code source, créé un nouvel objet DOM <script> et a de facto exécuté le code Javascript à l'intérieur !

Voici où le danger réside, un utilisateur mal intentionné pourrait attacher un script bien plus dangereux qu'une simple boîte d'alerte à l'URL et l'envoyer à un autre utilisateur naïf qui l'exécuterait à son tour.


Sécuriser son code

 

Nous avons donc compris l'importance de corriger une telle faille, mais alors comment s'y prendre pour sécuriser son code et éviter ce type attaque ?
Vous connaissez le dicton "Ne jamais faire confiance à l'utilisateur", et bien dans ce contexte il prend tout son sens.
Il faut filtrer toute entrée de l'utilisateur qui pourrait être affichée dans le navigateur, et donc encoder les entités HTML contenues dans les chaines de caractères.

Par exemple en PHP, on utilise souvent la fonction htmlentities() qui répond parfaitement à ce besoin.
Voici le code maintenant sécurisé de cutes-puppies.com :
 

<h1>Cute Puppies!</h1>
	<form action="/" method="GET">
		<input type="text" name="search" placeholder="Entrez le nom du chiot..." />
		<input type="submit" value="Envoyer">
	</form>
<p>Vous recherchez : <?= htmlentities($searchValue) ?></p>



Failles XSS stockées (Stored XSS)
 

Description
 

Une faille XSS est dite stockée ou persistante lorsque le script malveillant est déjà présent sur le serveur.
Le principe d'exécution de code indésirable est similaire à la version XSS reflétée sauf qu'ici code malveillant persiste dans le temps et rien n'est détectable depuis la charge utile de la requête HTTP, tout est déjà dans la base de données, vicieux ! 💀
 

Exemple

 

L'exemple le plus classique est celui d'un forum.
L'attaquant a envoyé un message qui contient le script malveillant sur le post d'un forum. Le message est alors stocké dans la base de données du serveur et affiché à quiconque naviguerait sur le post du forum, le script est alors exécuté.

Voici un exemple de ce qu'aurait pu être la faille XSS sur cute-puppies.com mais en version stockée cette fois !

Capture d'écran du site qui sert d'exemple pour la faille XSS stockée.


Sécuriser son code

 

Exactement comme pour sécuriser une faille XSS reflétée, il suffit d'encoder les entités HTML des entrées utilisateurs que l'on affiche dans nos pages.



Failles XSS basées sur le DOM (DOM-Based)

 

Description

 

Une faille XSS basée sur le DOM a lieu lorsqu'un attaquant parvient à injecter un script malveillant en manipulant seulement le DOM, cette faille est donc exploitable uniquement côté client.
L'exploitation de cette faille est souvent rendue possible à cause de fonctions Javascript qui impriment directement des entrées utilisateurs non encodées dans le DOM.
 

Exemple


Toujours avec cute-puppies.com, prenons l'exemple où l'on souhaiterait afficher une page plus détaillée d'un chiot.
Le développeur peu précautionneux de ce site décide d'écrire le code suivant :
 

<p>Nom du chiot : </p>
<script>
	const url = document.URL;
	const index = url.indexOf("nom=") + 4;
	const nameValue = decodeURIComponent(url.substring(index));
	document.write(nameValue);
</script>


Dans cet extrait de code, on comprend que l'on attend un paramètre nom venant de l'URL, lequel sera récuperé côté client puis décodé (pour éviter les accents encodés par exemple) et enfin affiché.

Si un utilisateur rentre l'URL suivante : https://cute-puppies.com/detail?nom=Shiba, aucun problème. "Shiba" sera affiché.

La faille est exploité de la façon suivante : https://cute-puppies.com/detail?nom=<script>alert('Hello World!')</script>

Ici on comprend que la chaine de caractères <script>alert('Hello World!')</script> est passé directement décodée dans la méthode document.write(), celle-ci est alors parsée pour créer un nouvel objet du DOM script et le code s'en retrouve exécuté.

Une autre mauvaise habitude en Javascript est d'utiliser la propriété innerHTML (ou html() en jQuery) pour insérer tout et n'importe quoi dans un élément :
 

<p>Nom du chien : <span id="nom"></span></p>

<script>
	const url = document.URL;
	const index = url.indexOf("nom=") + 4;
	const nameValue = decodeURIComponent(url.substring(index));
	const nameElement = document.getElementById("nom");
	nameElement.innerHTML = nameValue; // Mauvaise pratique
</script>


Préférez alors l'utilisation de la propriété innerText lorsque vous souhaitez afficher uniquement du texte, les entités HTML seront alors encodées.


 

Conclusion


Les failles XSS ont encore de beaux jours devant elles, et il est de notre devoir pour la sécurité de nos utilisateurs de s'en débarrasser.
Certains outils en ligne de pentest existent pour détecter si vos sites sont exploitables par XSS, beaucoup sont payants, mais Pentest Tools a une version light plutôt intéressante.


D'autres articles à découvrir :

0 commentaire