Jouez le jeton de la sécurité

Tas de jetons

Pourquoi utiliser un jeton

Aujourd’hui je vais vous parler de sécurité. En particulier de la protection contre les failles CSRF (ou XSRF), car ce type de faille est très peu connu et laisse énormément de possibilités à l’attaquant.

Le principe de l’attaque par CSRF est très simple : « Je ne peux pas faire une action, alors je m’arrange pour que l’administrateur la fasse à ma place (sans qu’il soit au courant bien entendu) ».

Prenons par exemple un forum qui n’aurai pas pensé à se protéger contre cette faille, et qui utiliserait une page nommé supprimer_article.php pour supprimer un article dont le numéro serait passé via la méthode GET (exemple : supprimer_article.php?id=4).

Nous pouvons alors créer une page HTML avec le code ci-dessous :

<img src="http://www.forumfaible.fr/supprimer_article.php?id=4" alt="Bienvenu sur ma page"/>

Lorsque l’administrateur du forum www.forumfaible.fr viendra voir ma page, son navigateur va essayer de charger l’image ce trouvant à l’adresse indiquée par la balise img (sans ce douter que ce n’est pas une image). Le serveur du forum va donc exécuter la page et supprimer l’article en croyant que c’est l’administrateur qui a demandé la suppression.


Installer un jeton

Mettons-nous maintenant à la place du forum qui veut se protéger contre cette faille. Ne prenez pas peur, c’est une technique très facile à mettre en place.

Il faut trouver un moyen de vérifier que l’action a été faite par l’administrateur et que seul lui pouvait la demander volontairement : nous allons utiliser sa session. En effet la session est stocké dans un dossier « hors web » et ne peux être lu que si on est nous même la personne connectée.

Nous mettrons donc en session une valeur qui ne peux pas être trouvée par un intrus et nous placerons cette valeur dans chaque lien, formulaire ou tout autre action.

Tout d’abord, mettons la valeur dans la session de l’utilisateur lorsque il se connecte :

$_SESSION['le-super-jeton'] = md5(uniqid(rand(), true));

Utilisez le code ci-dessous pour sécuriser vos liens :

<img src="http://www.forumfaible.fr/supprimer_article.php?id=4&amp;jet=<?php echo $_SESSION['le-super-jeton']; ?>" alt="Bienvenu sur ma page"/>

Et celui ci-dessous pour vos formulaires :

<input type="hidden" name="jet" value="<?php echo $_SESSION['le-super-jeton']; ?>"/>


Vérifier le jeton

A chaque fois qu’un formulaire est validé, qu’un lien est cliqué ou qu’action a été effectuée, il faut vérifier que le jeton envoyé avec l’action corresponde bien à celui enregistré en session.

<?php
  if( !empty($_SESSION['le-super-jeton']) && $_SESSION['le-super-jeton']==$_GET['jet'] ){
    // Ici le jeton est validé
  }else{
    // Ici c'est une tentative de CSRF
  }
?>


Jouer les gros jetons

Nous pouvons créer des jetons encore plus puissants pour sécuriser les actions de criticité élevée telles que la suppression d’un inscrit ou l’envoi de mail.

Ces jetons seront générés à chaque fois qu’une action critique est demandée. Supposons la suppression d’un utilisateur : « A chaque fois que l’administrateur demandera la suppression d’un utilisateur, on lui affichera une page intermédiaire qui lui demandera de confirmer son choix. Sur cette page se trouvera le gros jeton qui sera valide pour 5 minutes. Après ces 5 minutes, la confirmation sera rendu impossible et l’administrateur sera obligé de redemander la suppression. »

Ainsi, même si un pirate arrive à trouvé au hasard le jeton, il n’aura que 5 minutes pour tenter de piéger l’administrateur (qui aura sûrement déjà utilisé le jeton).

Nous allons donc créer deux fonctions, une qui crée un jeton à durée limitée et une qui vérifiera un jeton.

Créer un jeton

Un jeton sera identifié par 3 valeurs : son numéro, sa date d’expiration et sa catégorie (qui différenciera les actions de suppression et les actions d’envoi de mail) :

function create_token($category){
  $num = md5(uniqid(rand(), true));
  $date = time() + 5*60;
 
  $_SESSION['jetons'][$num] = array(
    'category'=>$category,
    'date'=>$date
  );
 
  return $num;
}
 
// exmple d'utilisation :
echo '<input type="hidden" name="jet" value="'.create_token('del_user').'"/>';

Vérifier un jeton

La fonction ci-dessous permettra de vérifier la validité d’un jeton :

function check_token($category, $token){
  if( is_array($_SESSION['jetons']) && is_array($_SESSION['jetons'][$token]) && $_SESSION['jetons'][$token]['category']==$category && $_SESSION['jetons'][$token]['date']<time() ){
    unset($_SESSION['jetons'][$token]);
    return true;
  }
  return false;
}
 
// exemple d'utilisation :
if( check_token('del_user', $_POST['jet']) ){
  echo 'OK';
}else{
  echo 'FAUX';
}
Tagués avec : , , , , ,
Publié dans PHP
3 commentaires pour “Jouez le jeton de la sécurité
  1. Thomas Prost dit :

    Félicitations pour votre article et pour ce site simple mais bien expliqué.

  2. Yannick Losbar dit :

    De même.

  3. Vincent dit :

    Merci à vous pour ce site à la fois utile et précis.
    Il y a parfois tellement sur le net que l’on peine a trouver ce que l’on cherche… Mais aujourd’hui je découvre vos articles avec plaisir !

Laisser un commentaire

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

*