Leçon 15 / 18

Repérer les opérations à risque

25 min PHP 8 — premiers scripts et formulaires Gratuit

Objectif : Empêcher une requête externe de déclencher une modification du carnet à l’insu de l’utilisateur.

Une personne est connectée à votre carnet et visite un autre site. Si ce site peut provoquer l’envoi d’une requête de suppression, le navigateur risque d’y joindre automatiquement le cookie de session : le serveur pourrait alors confondre cette requête avec une action volontaire. Vous allez ajouter une vérification côté serveur pour les opérations qui modifient les contacts.

Cette leçon complète le contrôle d’accès déjà mis en place : l’authentification vérifie qui effectue la requête, tandis que le jeton CSRF aide à vérifier que l’action provient d’un formulaire rendu par votre carnet. Le jeton ne remplace ni la session ni l’appel à exiger_authentification() dans une page privée.

Créer et vérifier un jeton CSRF

Un jeton CSRF est une valeur imprévisible conservée dans la session et envoyée dans le formulaire. À la réception, le serveur compare le jeton soumis avec celui de la session. Voici les fonctions à ajouter à includes/fonctions.php, après les fonctions déjà présentes. Elles utilisent la session démarrée par votre configuration existante et ne produisent pas de HTML.

PHP
function jeton_csrf(): string
{
    if (!isset($_SESSION['jeton_csrf'])) {
        $_SESSION['jeton_csrf'] = bin2hex(random_bytes(32));
    }

    return $_SESSION['jeton_csrf'];
}

function jeton_csrf_valide(mixed $jeton_soumis): bool
{
    return is_string($jeton_soumis)
        && isset($_SESSION['jeton_csrf'])
        && is_string($_SESSION['jeton_csrf'])
        && hash_equals($_SESSION['jeton_csrf'], $jeton_soumis);
}

random_bytes() produit une valeur aléatoire ; bin2hex() la transforme en chaîne transportable dans un champ HTML. hash_equals() effectue la comparaison de manière adaptée à un secret. Le paramètre est de type mixed afin que la fonction rejette aussi une valeur POST qui n’est pas une chaîne, au lieu de supposer que toute entrée reçue est correcte.

Protéger une opération envoyée en POST

Dans chaque formulaire qui modifie les données — ajout, modification ou suppression — ajoutez un champ caché dont la valeur vient de jeton_csrf(). Le formulaire de suppression est envoyé en POST : son champ id existant reste présent, et vous ajoutez le jeton à côté. Les inclusions communes de l’en-tête et du pied de page restent inchangées.

PHP
<input
  type="hidden"
  name="jeton_csrf"
  value="<?= htmlspecialchars(jeton_csrf(), ENT_QUOTES, 'UTF-8') ?>"
>

Dans contact-supprimer.php, contrôlez l’authentification, puis vérifiez la méthode et le jeton avant d’appeler le traitement de suppression déjà prévu par votre projet. Placez ce contrôle avant toute modification du fichier JSON et avant tout rendu. Si le contrôle échoue, renvoyez une réponse interdite et arrêtez le script : ne poursuivez jamais l’opération avec un jeton manquant ou invalide.

PHP
exiger_authentification();

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit;
}

if (!jeton_csrf_valide($_POST['jeton_csrf'] ?? null)) {
    http_response_code(403);
    exit;
}

// À cet endroit seulement : validez l’identifiant reçu,
// puis appelez le traitement de suppression existant.
Résultat attendu
Un accès direct en GET reçoit le statut HTTP 405. Une soumission POST sans jeton valable reçoit le statut HTTP 403. Seule une requête authentifiée en POST avec un jeton valable atteint le traitement de suppression.

Le commentaire indique l’emplacement du traitement existant : conservez ses fonctions et ses règles de validation au lieu d’inventer une nouvelle manière de stocker les contacts. Appliquez la même vérification aux pages d’ajout et de modification. Le champ caché n’est pas secret dans la page ; sa protection vient du fait que le site externe ne peut normalement pas lire la page de votre carnet pour récupérer le jeton associé à la session.

Réserver GET à la consultation

Une requête GET doit afficher des données ou effectuer une recherche, pas ajouter, modifier ou supprimer un contact. Une page privée qui reçoit une méthode inattendue peut refuser la requête, comme dans l’exemple précédent. Cette règle évite qu’un simple lien ou le chargement d’une image déclenche une modification ; elle complète le jeton, sans le remplacer.

Dans la prochaine leçon, vous construirez la liste des contacts et une recherche qui ne modifie pas les données du carnet.

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.