Leçon 11 / 20

Bloquer les requêtes CSRF

35 min PHP 8 — architecture, tests et sécurité Gratuit

Objectif : Refuser une opération de modification lorsque le formulaire ne présente pas un jeton valide.

Un formulaire de suppression ou de modification peut être envoyé depuis une page contrôlée par un tiers. Si le navigateur transmet automatiquement la session du carnet, votre application risque alors d’exécuter une action que vous n’avez pas initiée. Cette leçon ajoute une vérification qui refuse la requête avant qu’elle atteigne la logique de modification.

Une attaque CSRF (Cross-Site Request Forgery) cherche à faire exécuter une action par un utilisateur déjà authentifié, à son insu. Le navigateur peut joindre les cookies de session à une requête intersite ; l’application ne peut donc pas déduire de ces seuls cookies que le formulaire vient de son interface. Un jeton secret, propre à la session et vérifié sur chaque requête de modification, apporte cette preuve supplémentaire.

Créer un jeton lié à la session

Le composant JetonCsrf génère une valeur imprévisible avec random_bytes(), puis la conserve dans la session. Le formulaire reçoit cette valeur comme champ caché ; lors de son envoi, le serveur compare la valeur reçue à celle de la session. Le code ci-dessous est le contenu complet de src/Securite/JetonCsrf.php ; il suppose que la session a déjà été démarrée par l’application.

PHP
<?php

declare(strict_types=1);

namespace Atelier\Securite;

final class JetonCsrf
{
    private const CLE_SESSION = 'jeton_csrf';

    public function obtenir(): string
    {
        if (!isset($_SESSION[self::CLE_SESSION])) {
            $_SESSION[self::CLE_SESSION] = bin2hex(random_bytes(32));
        }

        return $_SESSION[self::CLE_SESSION];
    }

    public function estValide(?string $jetonRecu): bool
    {
        $jetonSession = $_SESSION[self::CLE_SESSION] ?? null;

        if (!is_string($jetonSession) || $jetonRecu === null) {
            return false;
        }

        return hash_equals($jetonSession, $jetonRecu);
    }
}

La méthode obtenir() conserve le même jeton pendant la session : la vue peut donc le demander pour remplir les champs cachés du formulaire et le formulaire de déconnexion. La méthode estValide() refuse aussi les valeurs absentes ou de mauvais type, puis emploie hash_equals() pour effectuer une comparaison à temps constant. Cette précaution évite de révéler des informations sur le jeton au fil des comparaisons.

Vérifier avant toute mutation

Le gabarit du carnet prévoit déjà un champ caché jeton_csrf dans les formulaires de connexion, de déconnexion, d’ajout ou modification et de suppression. Au rendu de la page, fournissez à ces champs la valeur retournée par obtenir(). À la réception d’un POST, contrôlez le champ correspondant avant d’appeler le service métier ou le dépôt ; une vérification placée après l’écriture ne protège pas l’opération.

Le contrôleur doit distinguer une requête invalide d’une opération acceptée. Par exemple, lorsqu’un POST de gestion ne contient pas un jeton valable, il renvoie le statut HTTP 403 et termine le traitement sans appeler le service. Si le jeton est valable, le contrôleur poursuit son parcours normal ; la validation des champs et l’exécution de l’action restent des étapes distinctes, abordées dans les parcours de gestion.

À retenir

  • Générez un jeton imprévisible avec une source cryptographique et conservez-le dans la session.
  • Insérez-le dans chaque formulaire qui déclenche une action protégée, sous le champ jeton_csrf.
  • Validez le jeton reçu avant tout appel qui modifie l’état du carnet ; en cas d’échec, refusez la requête, par exemple avec le statut 403.
  • Utilisez hash_equals() pour comparer les jetons et gardez la protection CSRF en complément de l’encodage HTML.

Dans la prochaine leçon, vous renforcerez la gestion des sessions en couvrant l’authentification, le renouvellement de l’identifiant et la fin de session.

Envie d'aller plus loin ?

Les cours Enovatic sont gratuits et le resteront. Si vous cherchez un accompagnement encadré, nos formations professionnelles sont animées par les mêmes formateurs.