Table des matières

Les attaques de type cross site scripting consistent en l'utilisation d'une application web pour déposer du code qui, affiché par d'autres utilisateurs du site, déclenche l'exécution de scripts plus ou moins hostiles.

Pour protéger les utilisateurs de Sympa des attaques de type “cross-site scripting”, David Verdin (CRU) a fait quelques recherches sur les attaques de ce type. Il synthétise dans cette page les informations glanées sur les sites :

Ces informations n'ont pas la prétention d'être exhaustives, mais nous vous les livrons car nous pensons qu'elles peuvent aider les développeurs d'applications web qui souhaitent protéger leurs applications contre ce type d'attaques.

Problématique

Cross-site quoi ?

Si vous n'avez jamais entendu parler de cross-site scripting (XSS), lisez quelques articles de fond avant de passer à la suite. Le principe du cross-site scripting est présenté dans plusieurs pages. Une bonne présentation synthétique se trouve dans wikipédia. Le site www.cgisecurity.com propose une FAQ claire.

En résumé, on peut dire que, dans notre contexte, un XSS est un appel à un script interprété côté client, dissimulé dans une chaine de caractère. Le gros du boulot est de contrer la dissimulation.

Objectif et limites du présent texte.

Les recherche menées ici ont eu pour contexte le développement de Sympa. Notre objectif était principalement d'empêcher les attaques de première et troisième catégories, c'est-à-dire empêcher l'injection de code hostile dans les données stockées par Sympa. Ceci est possible via les champs de formulaire de l'interface Web, par l'intermédiaire du gecos des adresses mails et enfin dans les requêtes SOAP. On trouve facilement des exemples de XSS et la manière dont ils agissent. En revanche, certainement en raison de la grande variabilité des failles exploitées, on a du mal à trouver des expressions rationnelles permettant de les détecter. Par ailleurs, les attaques XSS étant fondées sur les exceptions (principalement, dans notre contexte, la nécessaire souplesse des navigateurs vis à vis du HTML mal formé) il est peu probable qu'une expression rationnelle puisse les intercepter toutes. Nous cherchons donc avant tout à comprendre le fonctionnement des attaques XSS pour évaluer les outils qui nous permettront de les contrer.

Enfin, prenez note que ce document est un document de travail, pas une solution miracle. Nous espérons cependant qu'il vous aidera à protéger vos applications.

Préambule : les navigateurs

Lorsque vous testez la vulnérabilité de votre application au XSS, considérez que la plupart des attaques un peu raffinées exploitent un comportement particulier d'un navigateur spécifique. Tous ne présentent pas les mêmes failles.

Chaînes dangereuses

On peut synthétiser quelques informations sur les chaînes de caractères pouvant être sources de cross-site scripting (XSS dans la suite).

Les XSS ont la structure suivante :

Sauf exceptions (présentées plus bas), la chaîne peut être décomposée ainsi :

Contexte

C'est comme un médicament : il faut un principe actif et un excipient. Le principe actif est la molécule qui va agir, mais elle est inutile si elle n'est pas mélangée à l'excipient chargé de l'amener à bon port.

Le rôle du contexte est de faire passer les barrières au code hostile.

Exemple : une bonne vieille balise XML qui contient une section CDATA avec des balises et un script encodés en HTML. tout ça analysé par le navigateur donnera une script interprété. Mais si on se contente d'une recherche sur une chaîne genre ”<SCRIPT*”, on n'obtiendra jamais de résultat.

L'exemple ci-dessous a l'air de marcher sous IE 6 et 7. Pas sur Firefox ;)

<XML ID=I><X><C><![CDATA[<IMG SRC="javas]]><![CDATA[cript:alert('XSS');">]]>
</C></X></xml><SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML></SPAN>

Ça peut aussi tout simplement être des espaces vides, ou la fermeture d'une autre balise (</title> par exemple).

Chevron ouvrant

Les chevrons, notamment, peuvent être encodés (couramment en HTML ”&lt;”) pour ne pas être repérés par les expressions rationnelles. L'auteur du florilège propose la liste suivante d'encodages différents pour le chevron ouvrant, en combinant HTML et javascript (en UTF-8). Il précise que “la plupart ne donneront rien, mais certains peuvent être correctement interprétées suivant certaines circonstances.”

Les balises

La liste suivante contient les balises pouvant introduire un attribut contenant un script.

On peut aussi bien tous les interdire si on veut, ou bien en interdire la majorité et ne traiter les cas particuliers que pour ceux qu'on veut laisser utilisables.

En règle générale, il ne faut plutôt rechercher une balise ouvrante et en rester là. Il est en effet possible, dans certains cas, de ne pas fermer une balise, et son code sera tout de même interprété !

Les séparateurs

Ce qu'il y a après la chaîne “chevron ouvrant+balise” (telle que ”<SCRIPT”, par exemple) peut fortement varier. La balise peut être fermée et c'est son contenu qui est dangereux, ou bien elle est encore ouverte et on doit chercher le script dans ses attributs. Il existe même des méthodes permettant de faire croire que la balise est ouverte alors qu'on va la fermer juste après.

Voici un florilège de “trucs qu'on peut trouver apès une balise” :

Les chaînes introduisant les scripts

Ce ne sont pas des balises ni des séparateurs. Ce sont des noms d'attributs ou bien des couples “nom/valeur” qui permettent l'activation de comportements favorables à l'interprétation d'un script. Certains ne sont valables que dans des contextes très précis, d'autres sont beaucoup plus versatiles. Je présente les attributs ci-dessous (avec, entre parenthèses, le contexte dans lequel l'attirbut était présenté dans le site web où j'ai trouvé l'exemple)

En règle générale, tout ce qui permet d'introduire une source externe est potentiellement suspect. Toute référence à une image (par une balise, un attribut ou un élément de style) ou une feuille de style, etc. permet d'introduire un XSS.

Camouflage

L'ensemble des chaînes de caractère pré-décrites peuvent être camouflées de diverses manières pour passer les filtres. Voici certains des moyens employés à cet effet :

Le script lui-même

Ce peut-être soit une chaîne de caractère contenant le texte du script, soit un pointeur vers la source du script, généralement un fichier ”.js”, mais ce peut être également un faux fichier image, ou un fichier ”.htc”.

Ce dernier (HTML component) est un mécanimse d'internet explorer pour externaliser une parti de la page web. C'est un document HTML qui contient des scripts et des éléments propres à la syntaxe HTC. Voir http:msdn2.microsoft.com/en-us/library/ms531018.aspx . ===== Exceptions ===== Il existe également des formes d'introduction de scripts qui n'ont rien à voir avec des balises (donc beaucoup plus pénibles à introduire dans une expression rationnelle). Le plus pénible est l'actionscript : <code> a=“get”; b=“URL(\””; c=“javascript:”; d=“alert('XSS');\”)”; eval(a+b+c+d); </code> L'auteur du florilège évoque également SSI et PHP, mais ces failles imposent de pouvoir lancer des scripts locaux à partir de l'interface. Comme il le dit (à peu près) lui-même : “si on peut faire ça sur votre serveur, vous avez des problèmes autrement plus graves que le XSS”. Enfin, certaines chaînes de caractère semblent absolument innoffensives, pour la bonne raison qu'elles ne font qu'introduire des fichiers contenant le code hostile. La plus célèbre est certainement : <code><style src=“http:mon.site.de.sale.type/xss.css”/></code>

Conclusion

Se protéger contre les attaques XSS est un véritable cass-tête. On trouvera toujours un tordu pour contourner notre belle protection. :-(

Il est possible, pour se protéger du XSS, d'interdire purement et simplement tous les caractères susceptibles d'être employés pour créer un script. Un des problèmes de cette solution est qu'elle prive l'utilisateur d'un certain nombre de caractères qu'il peut vouloir employer pour des raisons tout-à-fait légitimes (le point-virgule, le chevron ouvrant, etc.). Elle est donc complètement innapplicable, je ne l'évoque que parce qu'elle m'est passée par la tête dans un instant de faiblesse. Un autre problème est que les coupables, dans les XSS, ne sont pas des caractères vus isolément mais bien des séquences de caractères présentant une grande varibalité.

En ce qui nous concerne nous avons essayé d'identifier, à travers des expressions rationnelles, les différentes séquences permettant d'injecter du code hostile. Ce fût un échec cuisant : interdiction de requêtes légitimes, attaques particulièrement sournoises qui passaient tout de même, notre approche a atteint bien vite ses limites.

Il nous apparaît qu'un groupe isolé a bien peu de chances de résoudre ce problème et que seule la confrontation d'expériences variées permettra de produire des solutions efficaces. Nous nous tournons donc vers des bibliothèques perl spécialisées.

Les attitudes généralement observées sont :

  1. pour les chaînes qui ne sont pas des balises : on échappe les caractères dangereux, comme les guillemets. C'est une solution efficace pour tout ce qui doit juste être affiché dans une page web. Quand on édite un fichier de script via une interface web, ça pose des problèmes pour l'interprétation future du script. Dès lrs, on pourrait se contenter d'un filtrage à l'affichage, mais quid du transfert de données ? Des copies de texte ?
  2. pour les balises : on crée des régles de validation des balises et des attributs
    1. interdire certaines attributs ou balises
    2. filtrer leurs valeurs (notamment interdire des liens vers des fichiers extérieurs au domaine de l'application)

Enfin, il nous semblerait intéressant de disposer de programmes “anti-xss” tout comme il existe des anti-virus, indépendants de l'application web, et chargés de vérifier les flux entrant de l'application. Nous sommes conscients de la complexité d'une telle entreprise, surtout dans le cadre d'une application web : la degré de suspicion accordé à une chaîne de caractère dépend alors du contexte dans lequel cette chapine est introduite, lequel est défini en fonction de l'application.