Se protéger contre les CSRF

Se protéger contre les attaques CSRF demandent de refondre totalement le fonctionnement de l'application vulnérable. Tout d'abord il sera nécessaire d’obfusquer son fonctionnement. Ainsi on évitera de mettre en place des formulaires sensibles dont les variables sont passées via les paramètres GET. En effet les variables GET sont utilisées afin d'accéder à des ressources et non pas afin d'émettre des données.

Mais cette obfuscation ne ferait que décourager les moins motivés. Pour empêcher réellement toutes exploitations il faudra mettre en place un token CSRF. Ce token devra être créé aléatoirement pour chaque utilisateur et stocké côté serveur dans une variable de session.

Ainsi lorsque l'utilisateur se connectera à l'application, un token sera créé:

<?php
session_start();
$_SESSION["user"] = "Defte";
$_SESSION["token"] = bin2hex(openssl_random_pseudo_bytes(10));
?>

Ensuite sur chaque formulaire impliquant une action de l'utilisateur il faudra ajouter ce token CSRF dans un champ caché:

<h1>Effectuer un virement bancaire :</h1>
<form action="#" method="post">
   <label>Email de l'expéditeur</label>
   <input type="text" name="expediteur"/>
   <br>
   <label>Email du destinataire</label>
   <input type="text" name="destinataire"/>
   <br>
   <input name="token" value="<?= $_SESSION["token"]; ?>" type="hidden">
   <input type="submit" value="Envoyez"/>
</form>

Puis côté serveur il faudra à chaque fois vérifier que le token émis dans le formulaire correspond bien au token stocké dans les variables de session de l'utilisateur:

<?php 
if(isset($_POST["expediteur"]) and isset($_POST["destinataire"])){
   if($_POST["token"] !== $_SESSION["token"]){
        echo "Did you just try to hack us ? :D";
   }
   else{
        echo "Virement effectué";
   }
}
?>

Si c’est le cas alors la requête est validée sinon elle est annulée. Le token CSRF devra bien évidemment être recréé à chaque nouvelle création de sessions afin d'empêcher tout brute force/rejeu.