Protection CSRF dans Symfony : le jeton des formulaires

La protection CSRF dans Symfony : un jeton placé dans chaque formulaire, qu'un autre site ne peut pas lire, pour refuser les requêtes forgées ailleurs.

// Le template envoie le jeton dans un champ caché :
// <input type="hidden" name="_token" value="{{ csrf_token('supprimer-plat-' ~ plat.id) }}">

#[Route('/cuisine/plat/{slug:plat}/supprimer', methods: ['POST'])]
public function supprimerPlat(Plat $plat, Request $request): Response
{
    if (!$this->isCsrfTokenValid('supprimer-plat-'.$plat->getId(), $request->request->getString('_token'))) {
        throw new AccessDeniedHttpException('Jeton CSRF invalide.');
    }
    // …
}

Une requête forgée part du navigateur de la victime, avec ses cookies : sans autre indice, le serveur la prend pour une action légitime. Le jeton fait la différence. Le composant Form l'ajoute et le vérifie tout seul, dans un champ caché _token. Pour un formulaire écrit à la main, on le fabrique avec csrf_token() dans Twig et on le contrôle avec isCsrfTokenValid() dans le contrôleur, comme ci-dessus. Les pièges classiques : un identifiant de jeton qui diffère entre le template et le contrôleur, et chaque envoi est refusé ; une suppression déclenchée par un simple lien en GET, qu'aucun jeton ne protège.

Les exercices passent du formulaire généré par le composant Form à un formulaire POST écrit à la main pour retirer un plat de la carte, avec un jeton propre à chaque plat, puis à un formulaire maudit dont le jeton ne correspond plus.

3 exercices font travailler cette notion, en écrivant du code dans le navigateur.

Dans les parcours

Notions voisines

FormulaireDébogage