PHP Contrefaçon de requête intersite


Exemple

Problème

Cross-Site Request Forgery ou CSRF peut forcer un utilisateur final à générer sans le savoir des requêtes malveillantes sur un serveur Web. Ce vecteur d'attaque peut être exploité à la fois dans les requêtes POST et GET. Supposons par exemple que le point de terminaison url /delete.php?accnt=12 supprime le compte transmis depuis le paramètre accnt d'une requête GET. Maintenant, si un utilisateur authentifié rencontrera le script suivant dans une autre application

<img src="http://domain.com/delete.php?accnt=12" width="0" height="0" border="0">

le compte serait supprimé.

Solution

Une solution commune à ce problème est l'utilisation de jetons CSRF . Les jetons CSRF sont incorporés dans les requêtes afin qu'une application Web puisse être certaine qu'une requête provient d'une source attendue dans le cadre du flux de travail normal de l'application. Tout d'abord, l'utilisateur effectue certaines actions, telles que l'affichage d'un formulaire, qui déclenche la création d'un jeton unique. Un exemple de formulaire mettant en œuvre cela pourrait ressembler à

<form method="get" action="/delete.php">
  <input type="text" name="accnt" placeholder="accnt number" />
  <input type="hidden" name="csrf_token" value="<randomToken>" />
  <input type="submit" />
</form>

Le jeton peut ensuite être validé par le serveur par rapport à la session utilisateur après l'envoi du formulaire pour éliminer les demandes malveillantes.

Code exemple

Voici un exemple de code pour une implémentation de base:

/* Code to generate a CSRF token and store the same */
...
<?php
  session_start();
  function generate_token() {
    // Check if a token is present for the current session
    if(!isset($_SESSION["csrf_token"])) {
        // No token present, generate a new one
        $token = random_bytes(64);
        $_SESSION["csrf_token"] = $token;
    } else {
        // Reuse the token
        $token = $_SESSION["csrf_token"];
    }
    return $token;
  }
?>
<body>
  <form method="get" action="/delete.php">
    <input type="text" name="accnt" placeholder="accnt number" />
    <input type="hidden" name="csrf_token" value="<?php echo generate_token();?>" />
    <input type="submit" />
  </form>
</body>
...


/* Code to validate token and drop malicious requests */
...
<?php
  session_start();
  if ($_GET["csrf_token"] != $_SESSION["csrf_token"]) {
    // Reset token
    unset($_SESSION["csrf_token"]);
    die("CSRF token validation failed");
  }
?>
...

De nombreuses bibliothèques et frameworks sont déjà disponibles et ont leur propre implémentation de la validation CSRF. Bien que ce soit l'implémentation simple de CSRF, vous devez écrire du code pour régénérer dynamiquement votre jeton CSRF afin d'empêcher le vol et la fixation de jeton CSRF.