Développement

Sécuriser un webhook WhatsApp : vérification de signature

10 min de lecture24 octobre 2025

Sécuriser un webhook WhatsApp Cloud API : vérification de la signature SHA-256, gestion du secret, replay attacks et bonnes pratiques.

Sécuriser un webhook WhatsApp : vérification de signature

Un webhook WhatsApp reçoit en permanence des événements sensibles : messages entrants clients, statuts de livraison, mises à jour de templates. S'il n'est pas correctement sécurisé, un attaquant peut injecter de faux événements, empoisonner votre CRM, ou faire déclencher à tort des workflows métier. La signature HMAC-SHA-256 fournie par Meta est votre première ligne de défense. Encore faut-il l'implémenter correctement.

Comment Meta signe ses webhooks

À chaque POST envoyé vers votre endpoint, Meta ajoute un header X-Hub-Signature-256 qui contient une signature HMAC-SHA-256 du corps brut de la requête, calculée avec votre App Secret comme clé.

Le format est : sha256={hex_hash}.

Votre serveur doit recalculer la même signature avec le même App Secret et comparer les deux valeurs. Si elles diffèrent, la requête est rejetée immédiatement avec un HTTP 401.

Récupérer et protéger l'App Secret

L'App Secret se trouve dans le Meta Business Manager, section Basic Settings de votre application. Règles absolues :

  • Jamais en dur dans le code source.
  • Jamais commité sur Git.
  • Stocké dans un secret manager (Vault, AWS Secrets Manager, GCP Secret Manager, variables d'environnement chiffrées).
  • Rotation périodique recommandée (annuelle au minimum).

Étape critique : utiliser le body brut

L'erreur la plus répandue en développement Node.js, Python ou PHP consiste à parser le JSON avant de calculer la signature. Or Meta signe le body brut byte-à-byte. Toute reformatation (espaces, ordre des clés, encodage) casse la vérification.

Node.js Express

Configurer express.json({ verify: (req, res, buf) => { req.rawBody = buf } }) pour préserver le buffer original.

Python Flask

Utiliser request.get_data() qui retourne les bytes originaux, jamais request.json avant vérification.

PHP

Lire file_get_contents('php://input') une seule fois, en début de traitement, avant tout parsing.

Comparaison de signature en temps constant

Une comparaison de chaînes classique (==, strcmp) est vulnérable aux attaques par timing : un attaquant peut deviner la signature caractère par caractère en mesurant les micro-différences de temps de réponse.

Utilisez toujours une fonction de comparaison en temps constant :

  • Node.js : crypto.timingSafeEqual().
  • Python : hmac.compare_digest().
  • PHP : hash_equals().

Protection contre les replay attacks

La signature valide un message authentique, mais rien n'empêche un attaquant qui l'a intercepté (via un serveur mal configuré, un log qui fuite) de le rejouer plus tard. Deux stratégies complémentaires :

Timestamp de tolérance

Chaque event Meta contient un timestamp. Rejeter tout événement dont le timestamp est plus vieux que 5 minutes. Cela limite drastiquement la fenêtre d'exploitation.

Idempotency key

Utiliser l'id unique de chaque message WhatsApp comme clé d'idempotence. Stocker les ID traités dans Redis avec TTL de 24h ; refuser les doublons.

Vérification du token à l'inscription

Le premier échange avec Meta est une requête GET de vérification, avec les paramètres hub.mode=subscribe, hub.verify_token, hub.challenge. Votre endpoint doit :

  • Comparer le hub.verify_token reçu avec votre token secret (choisi lors du setup dans Meta).
  • Retourner le hub.challenge en clair si le token match.
  • Retourner HTTP 403 sinon.

Ce token n'a rien à voir avec la signature ; c'est un secret partagé de premier niveau qui prouve à Meta que vous êtes bien l'administrateur de l'endpoint.

Bonnes pratiques infrastructure

  • HTTPS obligatoire avec certificat valide, TLS 1.2 minimum, TLS 1.3 recommandé.
  • Endpoint dédié : ne pas exposer le webhook sur la même URL que votre API publique.
  • Rate limiting : Meta n'attaquera pas votre endpoint, mais un attaquant qui devine l'URL peut essayer de le saturer.
  • Timeouts stricts : Meta attend une réponse en moins de 20 secondes, mais votre traitement doit être bien plus rapide (idéalement sous 500 ms).
  • Traitement asynchrone : accuser réception immédiatement (HTTP 200) et traiter le payload dans une queue (RabbitMQ, SQS, Redis) pour éviter de perdre des événements en cas de pic.

Logging et audit

Logger systématiquement les tentatives de signature invalide avec IP source, User Agent, timestamp. Un pic soudain d'échecs 401 est souvent le signal d'une tentative d'intrusion active. Configurer une alerte au-delà d'un seuil (par exemple 100 échecs en 5 minutes).

Conformité conformité réglementaire

Les messages WhatsApp reçus contiennent des données personnelles (numéros, contenus). Leur traitement doit respecter la loi 09-08 : minimisation des données, durée de conservation limitée, chiffrement au repos, accès traçable. Documenter cette chaîne dans votre registre des traitements est essentiel en cas de contrôle conformité réglementaire.

Conclusion

Un webhook WhatsApp bien sécurisé combine vérification de signature stricte, protection replay, comparaison en temps constant et infrastructure durcie. Ces mesures s'implémentent en quelques heures mais évitent des incidents dont le coût de réputation et de mise en conformité peut se chiffrer en dizaines de milliers de MAD. La sécurité webhook n'est pas un chantier optionnel : c'est un préalable non négociable à toute mise en production sérieuse.

Testez Adrixis META gratuitement. Sept jours, sans carte.