Cross-Site Scripting (XSS)
1. Principe
L'OWASP considère la vulnérabilité à XSS comme une faille critique car elle est très répandue et facile à détecter. Les attaques s'appuient principalement sur les formulaires des applications Web. Les victimes sont les utilisateurs des applications Web vulnérables. L'ANSSI signale dans la note d'information CERTA-2002-INF-001-001 que les scripts frauduleux peuvent endommager la base de registre de la victime, afficher des formulaires dont les saisies seront envoyées à l'attaquant, récupérer les cookies présents sur la machine de la victime, exécuter des commandes systèmes et construire des liens déguisés vers des sites malveillants.
Y.-W. Huang, C.-H. Tsai, T.-P. Lin, S.-K. H., D.T. Lee et S.-Y. Kuo [10] indiquent que l'attaque XSS est également une attaque par injection car l'objectif de l'attaquant est de soumettre un code frauduleux à l'application. A. Kiezun, P. J. Guo, K. Jayaraman, M. D. Ernst [11] montrent qu'il existe en fait deux types d'attaque XSS.
L'attaque XSS par réflexion (reflected XSS) s'appuie sur le fait que l'application Web affiche ce que l'utilisateur vient de saisir dans un formulaire dans une page de résultat. Le navigateur de la victime exécute alors le code frauduleux généré dans la page de résultat. Tous les champs de formulaire sont donc une faille de sécurité potentielle que l'attaquant peut exploiter par XSS. L'attaquant crée un lien déguisé vers l'application Web dont un des paramètres contient du code JavaScript frauduleux. En utilisant ce lien, la victime fait exécuter par son navigateur le code JavaScript. Le Web 2.0 et ses systèmes de gestion de contenu ont popularisé cette attaque en permettant de publier des liens aisément et visibles sur tout le Web.
L'attaque XSS stockée (stored XSS) s'appuie sur le fait que l'attaquant réussisse à stocker dans la base de données du code frauduleux qui sera exécuté par la victime lorsqu'elle tentera d'afficher la donnée malveillante. Cette attaque est plus dangereuse que la première car le code fait partie intégrante des données de l'application Web et peut atteindre plusieurs victimes.
2. Exemples d'attaque
L'attaque XSS par réflexion peut être implémentée par différents moyens.
Le plus facile est d'utiliser un moteur de recherche vulnérable. Par exemple les outils de forum intègrent des formulaires pour recherche des messages par leur contenu. La page de résultat reprend généralement les mots-clés saisis. Il suffit alors de mettre comme paramètre de recherche un code JavaScript qui sera ensuite interprété par le navigateur de la victime. Pour réaliser cette attaque, il suffit de laisser un lien qui aura pour paramètre le code malveillant.
Figure 14 - Exemple de lien malveillant exploitant une faille XSS
Sélectionnez
http
:
//
www.forum-vulnérable.com/recherche.php?parametre=<script>alert(‘attaque
XSS')</script>
En cliquant sur ce lien, la victime lancera la recherche. Puis le moteur de recherche affichera le paramètre « <script>alert(‘attaque XSS')</script> » qui sera exécuté par le navigateur.
Des applications Web sont responsables de l'affichage des courriers électroniques : les webmails. Pour consulter son courrier, l'utilisateur va préalablement s'authentifier et ses informations d'identification seront stockées dans des cookies. Un courrier malveillant peut intégrer du code JavaScript qui sera interprété par le navigateur. Ce code sera capable de récupérer les cookies et envoyer les informations à l'attaquant.
L'attaque XSS stockée injecte du code malveillant dans la base de données. L'application Web suivante de type forum va permettre d'illustrer cette attaque. La table support de la démonstration est la suivante :
Figure 15 - Script SQL de création de la table « messages »
Sélectionnez
CREATE
TABLE
IF
NOT
EXISTS
`messages` (
`id` int
(11
) NOT
NULL
AUTO_INCREMENT COMMENT
'
identifiant
'
,
`numerosujet` int
(11
) NOT
NULL
COMMENT
'
numero
du
sujet
'
,
`redacteur` varchar
(30
) NOT
NULL
COMMENT
'
nom
du
redacteur
du
message
'
, `message` varchar
(4000
) NOT
NULL
COMMENT
'
contenu
du
message
'
,
PRIMARY
KEY
(`id`)
) ENGINE=
InnoDB DEFAULT
CHARSET=
latin1 AUTO_INCREMENT=
6
;
Le script PHP suivant est responsable de l'enregistrement d'un message. Comme une des informations saisies (le nom du rédacteur) est réaffichée, cela implique que ce code est vulnérable à une attaque XSS par réflexion.
Figure 16 - Script PHP pour l'insertion dans la table « messages »
Sélectionnez
<?php
//
recuperation
des
parametres
$
message
=
$
_GET
[
'
message
'
]
;
$
nom
=
$
_GET
[
'
nom
'
]
;
$
numsujet
=
$
_GET
[
'
numsujet
'
]
;
//
generation
de
la
requete
$
requeteSQL
=
"
INSERT
INTO
messages
VALUES
(
NULL
,
'
$
numsujet
'
,
'
$
nom
'
,
'
$
message
'
)
"
;
//
execution
de
la
requete
$
reponse
=
mysql_query
($
requeteSQL
);
//
affichage
du
resultat
echo
"
<
tr
>
<
td
>
&
nbsp
;
<
/
td
>
<
td
>
Merci
$
nom
de
votre
participation
.
Vous
venez
de
saisir
:
$
message
<
/
td
>
<
/
tr
>
"
;
?>
En saisissant comme message un code JavaScript malveillant, il sera enregistré dans la base de données.
Le script PHP suivant est responsable de l'affichage de l'ensemble des messages d'un sujet.
Figure 17 - Script PHP pour la recherche dans la table « messages »
Sélectionnez
<?php
//
recuperation
des
parametres
$
numsujet
=
$
_GET
[
'
searchsujet
'
]
;
//
generation
de
la
requete
$
requeteSQL
=
"
SELECT
*
FROM
messages
WHERE
numerosujet
=
$
numsujet
order
by
id
"
;
//
execution
de
la
requete
$
reponse
=
mysql_query
($
requeteSQL
);
//
affichage
du
resultat
echo
"
<
tr
>
<
td
>
Sujet
$
numsujet
<
/
td
>
<
td
>
"
;
while
($
resultat
=
mysql_fetch_assoc
($
reponse
)) {
echo
$
resultat
[
'
redacteur
'
]
.
"
:
"
.
$
resultat
[
'
message
'
]
.
"
<
br
>
"
;
}
echo
"
<
/
td
>
<
/
tr
>
"
;
?>
Lorsque des utilisateurs afficheront le fil des messages, le message frauduleux sera automatiquement envoyé aux navigateurs et interprété créant une attaque XSS.
3. Parade et bonnes pratiques
Les recommandations faites précédemment pour se prémunir des risques d'injection sont valables pour XSS. Cependant, transformer les six caractères douteux suivants suffit.
Figure 18 - Caractères spéciaux à remplacer par leur code
Sélectionnez
&  &
<  <
>  >
"  "
'  ' (' n'est pas recommandé)
/  /
Côté client avec JavaScript il faut vérifier les données saisies par les utilisateurs. Côté serveur, il faut vérifier les données récupérées en paramètre. Il faut rejeter toutes les données qui ne sont pas conformes à ce qui est attendu.
Pour éviter le vol de cookies par du code JavaScript, il est possible de positionner l'attribut de cookie HTTPOnly [8]. S'il est présent, le navigateur interdit au moteur JavaScript de lire ou écrire dans les cookies. Cet attribut est très peu utilisé par les applications Web, car tous les navigateurs ne le gèrent pas. Cependant il est préférable de l'utiliser car les navigateurs les plus populaires l'implémentent, ce qui diminue les risques liés aux cookies.
Figure 19 - Script PHP pour positionner l'attribut de cookie HTTPOnly
Sélectionnez
<?php
session.
cookie_httponly =
True
?>
Les navigateurs intègrent des protections contre XSS en interdisant l'exécution de code JavaScript qui modifie une page Web depuis une page Web ne portant pas le même nom de domaine.