Vous êtes sur la page 1sur 10

Scurisation des

failles CSRF
Par Argoneth

www.openclassrooms.com

Licence Creative Commons 4 2.0


Dernire mise jour le 4/12/2011

2/11

Sommaire
Sommaire ........................................................................................................................................... 2
Scurisation des failles CSRF ............................................................................................................ 3
CSRF, ksako? ..................................................................................................................................................................
Le jeton de scurit ou token ............................................................................................................................................
Le referer ...........................................................................................................................................................................
Autres conseils ..................................................................................................................................................................
Les bonus ..........................................................................................................................................................................

3
4
5
7
7

Rsum de nos fonctions ............................................................................................................................................................................................ 7


Pour approfondir .......................................................................................................................................................................................................... 9

Q.C.M. ............................................................................................................................................................................... 9
Partager ..................................................................................................................................................................................................................... 10

www.openclassrooms.com

Sommaire

3/11

Scurisation des failles CSRF

Par

Argoneth

Mise jour : 04/12/2011


Difficult : Intermdiaire

Dure d'tude : 1 heure

Bienvenue tous !
Aujourd'hui, je vais vous introduire une nouvelle faille de scurit, et vous expliquer comment vous en protger au mieux.
Si vous tes dveloppeur et que la notion de "token" ne vous dit rien, lisez vite ce tuto, on est peut-tre dj en train de vous
pirater !
Ce tutoriel concerne les sites PHP, vous devez donc matriser ce langage (c.f. : le tuto de M@teo21). Il est surtout utile
pour les sites en activit, et assez complets, puisque ceux-ci doivent reposer sur un systme de privilges.

C'est partiiiii !
Sommaire du tutoriel :

CSRF, ksako?
Le jeton de scurit ou token
Le referer
Autres conseils
Les bonus
Q.C.M.

CSRF, ksako?
Je suis sr que vous vous demandez :
Mais c'est quoi ce CSRF dont il nous parle depuis tout l'heure ?

Ah oui, j'avais oubli de vous expliquer !


CSRF signifie "Cross-Site Request Forgeries". Je vous donne un exemple :
Paul est newser d'un site, il peut donc ajouter, modifier, et supprimer une news, ce qu'un utilisateur du site lambda ne peut PAS
faire.
Jean est un de ces utilisateurs lambda, et il aimerait pirater le site de Paul !
Il va donc rcuprer l'adresse permettant de
supprimer une news, et envoyer un message priv Paul contenant une image dont l'adresse sera celle de la page de
suppression de news.
Et l, le navigateur entre en jeu. En essayant d'afficher l'image, il va aller sur la page web permettant de supprimer la news et donc
l'excuter. Or, Paul tait identifi en tant que newser, la news sera donc supprime car IL a affich la page.
Sur le mme principe, si Paul peut recevoir une requte ajax qui en s'excutant va poster ou modifier une news !
C'est--dire que Paul recevra un code javascript qui "forcera" le navigateur appeler la page que le pirate veut que Paul excute.
On va donc apprendre se protger de ces failles trs dangereuses, sachant qu'il n'existe pas de protection parfaite.

www.openclassrooms.com

Scurisation des failles CSRF

4/11

Avant d'entrer dans le vif du sujet, je prcise toutes fins utiles que cette faille ne s'applique pas uniquement au cas que je
prsente dans ce tuto (c'est dire le "piratage" d'un espace d'administration), mais peut-tre utilise dans de nombreux domaines
o le but est de faire gnrer une requte par le navigateur de la victime (pour truquer des votes par exemple).

Le jeton de scurit ou token


Alors, pour commencer, voyons la protection la plus courante.
Elle consiste stocker un jeton unique (clairement une suite de nombres et de lettres) associ la date d'affichage pour chaque
visiteur qui affiche un formulaire dans une session, et ce mme jeton dans un champ cach. Ceci permet que la personne qui
tente d'excuter la page est bien passe par le formulaire avant, o on lui a dlivr le jeton.
Ce qui donne :
Code : PHP
<?php
//On dmarre les sessions
session_start();
//On gnre un jeton totalement unique (c'est capital :D)
$token = uniqid(rand(), true);
//Et on le stocke
$_SESSION['token'] = $token;
//On enregistre aussi le timestamp correspondant au moment de la
cration du token
$_SESSION['token_time'] = time();
//Maintenant, on affiche notre page normalement, le champ cach
token en plus
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"
/>
<title>Mon formulaire anti CSRF</title>
</head>
<body>
<form id="form" name="form" method="post" action="traitement.php">
<p>Pseudo :
<label>
<input type="text" name="pseudo" id="pseudo" />
</label>
</p>
<p>E-mail :
<label>
<input type="text" name="email" id="email" />
</label>
</p>
<p>Nom :
<label>
<input type="text" name="nom" id="nom" />
</label>
<input type="hidden" name="token" id="token" value="<?php
//Le champ cach a pour valeur le jeton
echo $token;
?>"/>
</p>
<p>
<label>
<input type="submit" name="Envoyer" id="Envoyer"
value="Envoyer" />
</label>
</p>
</form>
</body>
</html>

www.openclassrooms.com

Scurisation des failles CSRF

5/11

Bon, jusque-l, c'est bon je pense... Les commentaires sont explicites.


Je rappelle que session_start() se place avant tout affichage, c'est souvent une cause d'erreurs inexpliques. Vous
pouvez outrepasser cette limitation grce aux fonctions ob_, mais c'est moins propre.
Ensuite, on passe la page du traitement, et vous vous rendrez compte qu'il est trs simple de se protger efficacement.
On va dj vrifier la prsence du token, de sa date dans la session, et du token envoy par POST. Donc, si la personne qui
excute la page n'est pas passe par le formulaire, a bloque...
Le token doit aussi tre valide, c'est--dire identique celui envoy par POST, et non-expir, c'est--dire que sa gnration ne
remonte pas trop longtemps.
Puis on vrifie aussi si le token de $_POST est le mme que celui de $_SESSION. Ce qui donne finalement :
Code : PHP
<?php
session_start();
//On va vrifier :
//Si le jeton est prsent dans la session et dans le formulaire
if(isset($_SESSION['token']) && isset($_SESSION['token_time']) &&
isset($_POST['token']))
{
//Si le jeton de la session correspond celui du formulaire
if($_SESSION['token'] == $_POST['token'])
{
//On stocke le timestamp qu'il tait il y a 15 minutes
$timestamp_ancien = time() - (15*60);
//Si le jeton n'est pas expir
if($_SESSION['token_time'] >= $timestamp_ancien)
{
//ON FAIT TOUS LES TRAITEMENTS ICI
//...
//...
}
}
}
//SINON, ON RAJOUTE DES ELSE ET DES MESSAGES D'ERREUR
?>

Je vous conseille si vous utilisez cette mthode sur plusieurs scripts de nommer vos sessions pour ne pas confondre
les jetons. Par exemple, $_SESSION['token_time'] devient $_SESSION['inscription_token_time'].
Voil pour la protection de base. Suivez le guide, on va rentrer dans d'autres petites scurits mettre en place pour bien gner le
pirate.
videmment, on peut utiliser un token pour des actions qui ne passent pas par un formulaire.
Par exemple : sur une page ou l'administrateur peut supprimer des news, il y a plusieurs liens vers : supprimer_news.php?id=34
Au lieu de transmettre le jeton par POST, on le transmet par GET, comme les autres donnes (en l'occurence l'ID de la news
supprimer). Le principe reste sinon le mme, mais le POST est plus sr.

Le referer
On va donc poursuivre notre long chemin vers la vrit.
Imaginons que le pirate fasse une injection CSRF et que, au moyen de requtes AJAX, il fasse afficher l'admin la page du
formulaire puis la page du traitement...
Une requte AJAX, c'est un code Javascript qui s'excute et qui appelle en arrire plan (c'est dire que c'est invisible pour

www.openclassrooms.com

Scurisation des failles CSRF

6/11

l'utilisateur) une page distante. Le javascript tant un langage client, c'est dire excut par l'utilisateur et non par le serveur, le
site qui reoit la requte AJAX est appel comme si l'utilisateur victime l'avait appel consciemment. C'est donc un moyen de
raliser une attaquer CSRF. Je vous renvoie vers ce tuto.
Eh bien l'injection serait russie

, car le token aurait bien t gnr par la page 1, et la vrification sera passe avec succs

sur la page 2, sauf si vous vrifiez que la page qui a conduit le visiteur la page de traitement est bien le formulaire, c'est dire
que le visiteur a cliqu sur un lien ou un bouton de la page 1 qui l'a directement conduit la page 2.
On peut vraiment faire a ?

Oui, bien sr, grce $_SERVER['HTTP_REFERER']. C'est une variable disponible n'importe o dans votre script sans rien faire
de particulier (comme toutes ses cousines $_SERVER['...']), et elle contient l'adresse, si elle existe, de la page qui a amen votre
visiteur sur le script en cours.
ATTENTION : cette variable renvoie une adresse absolue, par exemple http://lesite.com/dossier1/url_a_rallonge.html,
et non pas ../url_a_rallonge.html
Donc, on va rajouter un if qui vrifiera si cette variable est gale la page formulaire.php, je vous laisse trouver a tout seul (je
sais, je suis cruel
).
Ramassage des copies, et correction :
Secret (cliquez pour afficher)
Code : PHP
<?php
session_start();
//On va vrifier :
//Si le jeton est prsent dans la session et dans le formulaire
if(isset($_SESSION['token']) && isset($_SESSION['token_time']) &&
isset($_POST['token']))
{
//Si le jeton de la session correspond celui du formulaire
if($_SESSION['token'] == $_POST['token'])
{
//On stocke le timestamp qu'il tait il y a 15 minutes
$timestamp_ancien = time() - (15*60);
//Si le jeton n'est pas expir
if($_SESSION['token_time'] >= $timestamp_ancien)
{
//Si le referer est bon
if($_SERVER['HTTP_REFERER'] ==
'http://monserveur.com/leformulaire.php')
{
//ON FAIT TOUS LES TRAITEMENTS ICI
//...
//...
}
}
}
}
//SINON, ON RAJOUTE DES ELSE ET DES MESSAGES D'ERREUR
?>

Remplacez videmment l'adresse du formulaire par la bonne.


Le referer est envoy par le navigateur du client, en d'autres termes il est trs facile de le modifier ! Ne vous fiez donc
pas lui 100%, ce n'est qu'une protection complmentaire.

www.openclassrooms.com

Scurisation des failles CSRF

7/11

Voil, vous tes dj bien protgs, mais il y a encore quelques petites choses voir... On continue!

Autres conseils
Je vous rappelle qu'aucune protection n'est parfaite, mais que les pirates sont des feignants et donc s'ils doivent passer
50h avant de vous pirater, il vont chercher une autre victime !
Donc, premirement, passez le plus de donnes possibles en POST, a oblige monter une attaque avec des requtes AJAX,
puisque la technique de l'image (voir partie I) ne permet pas de passer des donnes en POST la page appele, mais seulement
en GET (dans l'URL).
De plus, la taille des URL est limite 255 caractres, donc a fait pas lourd.
Privilgiez le POST, mais avec discernement, pour passer un id dans l'URL, par exemple, profil.php?id_membre=1, pas la
peine d'utiliser POST, GET suffira bien.
Ensuite, on a oblig le pirate nous envoyer du code AJAX qui sera excut par l'administrateur. H, il me vient une ide, si on
l'empchait de le faire ? Allez, lanons-nous !
On va chapper les caractres HTML ncessaires par exemple le < et les ' " qui sont indispensables pour ce type d'attaque (ne
soupirez pas, c'est plus que simplissime). La plupart de vous doit s'en douter, on va utiliser htmlspecialchars().
Vous utilisez peut-tre dj htmlentities(), sachez que c'est htmlspecialchars() + d'autres choses, donc a convient trs
bien !
Il suffit donc de passer tout ce qui risque de contenir du code qui sera affich travers cette fonction, par exemple (vous pouvez
changer le nom des variables
):
Code : PHP
<?php
$chaine_securisee = htmlentities($chaine_a_risque);
?>

la poursuite de la protection parfaite

, vous pouvez aussi sur la page traitement demander une confirmation avant de

valider l'action. Donc, moins que le webmaster clique sur poursuivre, rien ne sera excut. Mais rservez cette technique aux
points cls du site, parce que c'est trs lourd !
Dans le mme ton, il est possible d'exiger une double connexion pour obtenir l'accs la partie d'administration, comme dans
certains forums PhPBB. Ainsi, on peut conserver une option de connexion automatique (bien pratique) sans risque, puisque si
l'administrateur veut se connecter l'administration, il devra se reconnecter.
Vous pouvez aussi sur le mme principe demander avant une action critique de retaper le mot de passe.
Enfin, je vous conseille de lire ce tuto, qui vous donnera des pistes pour contrer le vol de session, qui ici peut constituer une
faille dans le systme.
Il existe donc de nombreux moyens de vous protger, je ne les ai pas tous cits, et je vous invite donc vous documenter,
puisque le Web ne manque pas d'informations ce sujet, et de jeter un coup d'oeil la partie bonus ! L'idal est de choisir une ou
un ensemble de protections qui combinent praticit et efficacit, c'est dire le compromis entre scurit et ergonomie. L, vous
tes les seuls juges.

Les bonus
Rsum de nos fonctions
Vous tes encore l ? Trs bien, pour vous fliciter de votre persvrance, je vous ai rcapitul tout le code, videmment, vous
de l'adapter vos besoins.
Voici donc 2 petites fonctions qui rcapitulent les principales protections, pour les explications rfrez-vous aux commentaires :
Code : PHP

www.openclassrooms.com

Scurisation des failles CSRF

8/11

<?php
//Cette fonction gnre, sauvegarde et retourne un token
//Vous pouvez lui passer en paramtre optionnel un nom pour diffrencier les
formulaires
function generer_token($nom = '')
{
session_start();
$token = uniqid(rand(), true);
$_SESSION[$nom.'_token'] = $token;
$_SESSION[$nom.'_token_time'] = time();
return $token;
}
//**************************************************************************//
//**************************************************************************//
//**************************************************************************//
//Cette fonction vrifie le token
//Vous passez en argument le temps de validit (en secondes)
//Le referer attendu (adresse absolue, rappelez-vous :D)
//Le nom optionnel si vous en avez dfini un lors de la cration du token
function verifier_token($temps, $referer, $nom = '')
{
session_start();
if(isset($_SESSION[$nom.'_token']) && isset($_SESSION[$nom.'_token_time']) &&
isset($_POST['token']))
if($_SESSION[$nom.'_token'] == $_POST['token'])
if($_SESSION[$nom.'_token_time'] >= (time() - $temps))
if($_SERVER['HTTP_REFERER'] == $referer)
return true;
return false;
}
?>

Bon, je vous donne quand mme un exemple d'utilisation mes chers Zros. Voici la page du formulaire :
Code : PHP
<?php
$token = generer_token('forum');
//Ensuite, le formulaire normal, pensez au champ cach. ;)
?>

Et voici la page de traitement :


Code : PHP
<?php
if(verifier_token(600, 'http://test.fr/formulaire.php', 'forum'))
{
//TRAITEMENTS
//..
//..
}
else
{
//ERREUR
}
?>

www.openclassrooms.com

Scurisation des failles CSRF

9/11

Mais pourquoi met-on if(verifier_token(...)) ? a n'a aucun sens ?

Eh bien si : la fonction renvoie true si le token est valide, et false s'il est invalide, ce qui donne :
Si le token est valid : if(true), ce qui quivaut "si vrai", donc la condition est vrifie
Sinon, c'est if(false), si faux, condition non valide, on excute le else.

Pour approfondir
Si vous voulez en apprendre plus, je vous conseille les sites suivants :
Wikipdia
XMCOPartners(audit informatique)
MTI
Il est aussi intressant de voir comment les grands scripts open-source (PhPBB, Joomla, etc.) se protgent de ce genre
d'attaques. Les parades qu'ils dploient sont rflchies par toute une communaut, a les rend donc efficaces.Enfin,
j'attire votre attention sur le fait que certains frameworks facilitent la gestion de la scurit, nativement ou avec des
modules, comme Ruby on Rails, Django, etc.
Voil, c'est fini !

Q.C.M.
Le premier QCM de ce cours vous est offert en libre accs.
Pour accder aux suivants
Connectez-vous Inscrivez-vous
Qu'est-ce qu'une faille CSRF?
Un trou dans le CSRF
Une faille de scurit permettant un pirate de faire faire un admin ce qu'il veut
Un erreur dans PHP qui compromet la scurit
Un token non-gnr

Qu'est ce qu'un token?


Un jeton de scurit unique
Un champ cach particulier
a n'existe pas

Le referer est-il totalement sr ?


Non, car il est facilement modifiable
Oui, car c'est le serveur qui le dlivre
Non, car il se peut que le referer "bug"
Aucune ide

Correction !
Statistiques de rponses au Q CM

Vous avez appris vous protger contre un type de faille assez mconnu chez les dbutants. N'hsitez pas poster un
commentaire si vous avez un problme, j'y rpondrai, mais pas MP par contre.
Avant de nous quitter, je tiens remercier les diffrents Zr0s qui m'ont aid par leurs commentaires ajouter, modifier et
amliorer certains points du tuto. Je vous encourage aussi me faire part de vos commentaires, pour pouvoir avancer.
Enfin, je prcise, pour viter les critiques acerbes de certains, que ce tutoriel n'est qu'une introduction aux failles CSRF. Il ne les
traite pas exhaustivement, l'intrt tant surtout d'attirer l'attention des webmestres dbutants sur le fait qu'il existe des failles
trs dangereuses auxquelles on ne pense pas immdiatement, CSRF en tant un bon exemple.

www.openclassrooms.com

Scurisation des failles CSRF

10/11

Merci de votre lecture, bientt!

Partager
Ce tutoriel a t corrig par les zCorrecteurs.

www.openclassrooms.com

Vous aimerez peut-être aussi