Contexte
Le Cross-Site Scripting (XSS) représente une faille de sécurité Web qui permet à un attaquant de compromettre les interactions de l'utilisateur avec une application vulnérable. Les attaques XSS permettent habituellement à l'attaquant de se faire passer pour un utilisateur victime et de mener toutes les actions que cet utilisateur est capable d'effectuer, ainsi que d'accéder à toutes les données de l'utilisateur. Dans le cas où l'utilisateur victime a des privilèges dans l'application, l'attaquant pourrait prendre le contrôle total de toutes les fonctionnalités et données de l'application. Ces attaques se produisent en manipulant un site Web vulnérable pour qu'il renvoie du code JavaScript malveillant aux utilisateurs. Une fois que le code malveillant s'exécute dans le navigateur d'une victime, l'attaquant peut entièrement compromettre son interaction avec l'application.
L'exploitation d'une vulnérabilité de script intersite permet généralement à un attaquant de :
- Se faire passer pour l'utilisateur victime ou se faire passer pour lui ;
- Effectuer toute action que l'utilisateur est capable d'effectuer ;
- Lire toutes les données auxquelles l'utilisateur peut accéder ;
- Capturer les identifiants de connexion de l'utilisateur ;
- Effectuer une dégradation virtuelle du site Web ;
- Injecter une fonctionnalité cheval de Troie dans le site Web.
Les attaques XSS sont principalement de trois types :
- Le Reflected XSS, où le script malveillant provient de la requête HTTP actuelle ;
- Le Stored XSS, où le script malveillant provient de la base de données du site Web ;
- Le DOM-based XSS, où la vulnérabilité réside dans le code côté client plutôt que dans le code côté serveur.
Reflected XSS
Le Reflected XSS est considéré comme la catégorie la plus simple d'attaques XSS. Ce type d'attaque se produit lorsque l'application web reçoit des données dans une requête HTTP et les inclut dans la réponse immédiate sans prendre les mesures de sécurité nécessaires.
https://website.com/status?message=All+is+well.
<p>Status: All is good.</p>
Comme l'application ne traite pas les données reçues, un attaquant peut facilement créer une attaque XSS de type Reflected en exploitant cette faiblesse.
https://website.com/status?message=<script>/*+Bad+code+here...+*/</script>
<p>Status: <script>/* Bad code here... */</script></p>
Stored XSS
L'attaquant peut exploiter le XSS de type Stored, qui survient lorsqu'une application inclut des données d'une source non fiable dans ses réponses HTTP. Les données en question peuvent être soumises à l'application via des requêtes HTTP telles que des commentaires sur un article de blog, des surnoms d'utilisateurs dans une salle de discussion ou des coordonnées sur une commande client. Les données peuvent également provenir d'autres sources non fiables, telles qu'une application de messagerie Web qui affiche les messages reçus via SMTP, une application de marketing qui affiche des publications sur les réseaux sociaux ou une application de surveillance réseau qui affiche des paquets de données provenant du trafic réseau. Par exemple, dans une application de messagerie, les utilisateurs peuvent soumettre des messages qui sont affichés aux autres utilisateurs, ce qui peut potentiellement être exploité par un attaquant pour exécuter du code malveillant.
<p>Hello, this is a message!</p>
En exploitant une vulnérabilité XSS de type Stored dans une application de messagerie, un attaquant peut facilement envoyer un message malveillant qui compromet la sécurité des autres utilisateurs.
<p><script>/* Bad code here... */</script></p>
DOM-based XSS
Le XSS de type DOM-based se produit lorsqu'une application web contient du code JavaScript côté client qui manipule les données d'une source non fiable, souvent en réécrivant les données dans le DOM. Un exemple courant est lorsqu'une application utilise du JavaScript pour extraire la valeur d'un champ de saisie et écrire cette valeur dans un élément HTML.
var search = document.getElementById('search').value;
var result = document.getElementById('result');
result.innerHTML = 'Result: ' + search;
Si l'attaquant peut contrôler la valeur du champ de saisie, il peut facilement construire une valeur malveillante qui provoque l'exécution de son propre script :
Result: <img src=1 onerror='/* Bad code here... */'>
Dans un cas typique, le champ d'entrée serait rempli à partir d'une partie de la requête HTTP, telle qu'un paramètre de chaîne de requête d'URL, permettant à l'attaquant de lancer une attaque à l'aide d'une URL malveillante, de la même manière que XSS reflété.
Impact
L'impact réel d'une attaque XSS dépend généralement de la nature de l'application, de ses fonctionnalités et de ses données, ainsi que du statut de l'utilisateur compromis. Par exemple:
- Dans une application brochureware, où tous les utilisateurs sont anonymes et toutes les informations sont publiques, l'impact sera souvent minime.
- Dans une application contenant des données sensibles, telles que des transactions bancaires, des e-mails ou des dossiers médicaux, l'impact sera généralement grave.
- Si l'utilisateur compromis a des privilèges élevés au sein de l'application, l'impact sera généralement critique, permettant à l'attaquant de prendre le contrôle total de l'application vulnérable et de compromettre tous les utilisateurs et leurs données.
Trouver et tester les vulnérabilité XSS
Le test manuel du XSS reflété et stocké implique normalement de soumettre une entrée unique simple (telle qu'une courte chaîne alphanumérique) dans chaque point d'entrée de l'application, d'identifier chaque emplacement où l'entrée soumise est renvoyée dans les réponses HTTP et de tester chaque emplacement individuellement pour déterminer si une entrée correctement conçue peut être utilisée pour exécuter du JavaScript arbitraire. De cette façon, vous pouvez déterminer le contexte dans lequel le XSS se produit et sélectionner une charge utile appropriée pour l'exploiter.
Pour trouver des vulnérabilités basées sur DOM dans des entrées non basées sur des URL (telles que document.cookie) ou des récepteurs non basés sur HTML (comme setTimeout), rien ne remplace l'examen du code JavaScript, qui peut être extrêmement chronophage.
Comment prévenir les attaques XSS
Empêcher les scripts intersites est facile dans certains cas, mais peut être beaucoup plus difficile en fonction de la complexité de l'application et de la façon dont elle traite les données contrôlables par l'utilisateur. En général, la prévention efficace des vulnérabilités XSS implique probablement une combinaison des mesures suivantes :
- Filtrer l'entrée à l'arrivée
- Encoder les données en sortie : Selon le contexte de sortie, cela peut nécessiter l'application de combinaisons d'encodage HTML, URL, JavaScript et CSS.
- Utilisez les en-têtes de réponse appropriés : Pour prévenir le XSS dans les réponses HTTP qui ne sont pas destinées à contenir du HTML ou du JavaScript, vous pouvez utiliser les en-têtes Content-Type et X-Content-Type-Options pour vous assurer que les navigateurs interprètent les réponses comme vous le souhaitez.
- Politique de sécurité du contenu : Comme dernière ligne de défense, vous pouvez utiliser la politique de sécurité du contenu (CSP).