Voir “e-mail signé par” dans Gmail (ou des indices d’interface similaires dans d’autres clients) rappelle que l’identité et l’intégrité comptent dans les flux de travail e-mail. Mais si vous consommez des e-mails entrants via des webhooks (pour l’automatisation QA, la vérification d’inscription, ou les agents LLM), la limite de sécurité se déplace : votre vrai risque n’est souvent pas de savoir si le message SMTP avait DKIM, mais si la requête HTTP livrant l’e-mail analysé est authentique.
Ce guide explique ce que signifie réellement “e-mail signé par”, pourquoi ce n’est pas suffisant pour l’automatisation pilotée par webhook, et comment vérifier l’authenticité des charges utiles webhook d’une manière qui résiste aux tentatives, duplicatas et saisies adverses.
Si vous utilisez Mailhook spécifiquement, il prend en charge les notifications webhook en temps réel et les charges utiles signées pour les e-mails reçus sous forme de JSON structuré. Pour le contrat d’intégration canonique et à jour (en-têtes exacts, construction de signature et exemples), utilisez : mailhook.co/llms.txt.
Ce que signifie réellement “E-mail signé par”
La plupart des interfaces de boîte de réception affichent “signé par” lorsque le message a passé les vérifications d’authentification cryptographique, typiquement DKIM (DomainKeys Identified Mail). DKIM permet à un domaine expéditeur de signer des parties du message afin que les destinataires puissent détecter la falsification en transit et associer le message à un domaine.
Nuance importante :
- DKIM aide le destinataire à répondre “Ce message provient-il probablement d’un expéditeur autorisé pour ce domaine, et a-t-il été modifié en transit ?”
- DKIM n’authentifie pas la requête HTTP que votre système reçoit plus tard d’un fournisseur de webhook.
Même si un message est parfaitement signé DKIM, un acteur malveillant peut encore tenter de :
- Usurper votre endpoint webhook avec une fausse charge utile “nouvel e-mail reçu”
- Rejouer une ancienne charge utile valide pour re-déclencher un flux OTP
- Falsifier les champs JSON si votre vérification n’est pas calculée sur le corps brut
Donc traitez “e-mail signé par” comme un contexte utile pour l’e-mail lui-même, non comme un substitut à l’authentification webhook.
DKIM vs signatures webhook : deux problèmes de confiance différents
| Mécanisme | Ce qu’il authentifie | Où il s’applique | Ce qu’il ne vous protège pas contre |
|---|---|---|---|
| DKIM (affiché comme “e-mail signé par”) | Parties du message e-mail signées par un domaine | SMTP et réception de boîte mail | Appels webhook HTTP forgés, livraisons rejouées, votre propre pipeline d’analyse/normalisation |
| Signature webhook | Le corps de requête HTTP livré à votre endpoint | Votre limite d’application | Un e-mail “légitime” contenant du contenu malveillant (injection de prompt, liens SSRF, etc.) |
La meilleure pratique en automatisation est de vérifier les deux :
- Vérifiez la signature webhook pour prouver que la requête vient de votre fournisseur.
- Traitez le contenu e-mail comme une saisie non fiable même après que le webhook est vérifié.
Pour le contexte des normes DKIM, voir RFC 6376.
Modèle de menace : ce contre quoi vous vous défendez
Lorsque votre système reçoit du courrier entrant comme JSON via webhook, supposez que les attaquants tenteront des modes d’échec courants qui ressemblent aussi à un comportement normal de systèmes distribués :
- Usurpation : envoi de requêtes directement à votre endpoint webhook
- Rejeu : re-envoi d’une requête précédemment valide pour déclencher à nouveau des effets de bord
- Falsification du corps : exploitation de frameworks qui re-sérialisent JSON et vérifient accidentellement une représentation d’octets différente
- Confusion d’en-têtes : s’appuyer sur des listes d’IP autorisées ou des chaînes “User-Agent” au lieu de la vérification cryptographique
- Amplification de tentatives : déclencher de multiples actions en aval parce que votre gestionnaire n’est pas idempotent
Si votre consommateur en aval est un agent LLM, les enjeux sont plus élevés : un e-mail forgé ou rejoué peut devenir une injection d’instruction ou amener un agent à renvoyer des e-mails de vérification, cliquer sur des liens, ou exfiltrer des secrets.
Ce que “vérifier l’authenticité des charges utiles webhook” devrait signifier en pratique
Un flux de vérification webhook sécurisé inclut typiquement tout ce qui suit :
1) Vérifier une signature calculée sur le corps de requête brut
La seule séquence d’octets sur laquelle les deux parties peuvent s’accorder est le corps de requête HTTP brut. De nombreuses violations de webhook proviennent de la vérification d’un objet analysé (ou d’une chaîne JSON joliement formatée) plutôt que des octets exacts reçus.
Règles d’implémentation :
- Capturez les octets du corps brut comme votre framework les reçoit.
- Calculez la signature attendue en utilisant votre secret webhook.
- Comparez les signatures en utilisant une comparaison à temps constant.
La façon dont les signatures sont construites varie selon le fournisseur (HMAC, JWS détaché, signature asymétrique). Ne devinez pas les noms d’en-têtes ou les règles de canonicalisation.
Mailhook fournit des charges utiles signées pour les notifications webhook, mais vous devriez suivre le contrat exact dans mailhook.co/llms.txt.
2) Appliquer la tolérance d’horodatage pour réduire le risque de rejeu
Une signature seule prouve l’authenticité, mais pas la fraîcheur.
Ajoutez une exigence d’horodatage :
- Exigez un en-tête ou champ d’horodatage fourni par le fournisseur.
- Rejetez les requêtes plus anciennes qu’une petite fenêtre (communément 5 minutes, parfois 1 à 15 minutes selon les tentatives et files d’attente).
- Considérez la dérive d’horloge et fixez une tolérance explicite.
Si vous devez supporter des délais plus longs, combinez les vérifications d’horodatage avec le stockage de rejeu (section suivante).
3) Ajouter la détection de rejeu en utilisant un ID de livraison
Même les fournisseurs légitimes tentent à nouveau les webhooks. Les attaquants rejouent aussi.
Donc votre gestionnaire devrait :
- Extraire un identifiant d’événement stable (ID de livraison, ID d’événement, ID de message, ou clé d’idempotence spécifique au fournisseur).
- Le stocker avec un TTL dans un magasin de données rapide.
- Rejeter ou ne rien faire pour les duplicatas.
Ce n’est pas optionnel si votre webhook déclenche des effets de bord (marquer un OTP comme consommé, créer un compte, approuver un flux de travail).
4) Échouer fermé, et séparer “vérification” de “traitement”
Une conception propre est :
- Couche de vérification : signature, horodatage, vérifications de rejeu
- Couche de traitement : analyser JSON, dédupliquer par message/artefact, extraire OTP ou lien, mettre en file d’attente le travail
Si la vérification échoue :
- Retournez un 4xx (souvent 401/403) et ne mettez pas en file d’attente.
Si le traitement échoue :
- Retournez un 2xx seulement après avoir persisté en toute sécurité l’événement pour une tentative, ou retournez un 5xx pour que le fournisseur tente à nouveau. Choisissez intentionnellement.
5) Gardez les secrets hors des journaux et protégez l’endpoint
Hygiène minimale :
- Stockez les secrets webhook dans un gestionnaire de secrets.
- Faites tourner les secrets et supportez la validation double pendant la rotation.
- Utilisez HTTPS uniquement.
- Ne journalisez pas les signatures brutes, secrets, ou corps d’e-mails complets dans les journaux partagés.
Une liste de vérification de vérification agnostique au fournisseur (copier/coller pour les revues de code)
Utilisez ceci comme une porte de revue avant de laisser les agents ou pipelines CI faire confiance aux événements e-mail entrants :
- Le corps brut est capturé et utilisé pour la vérification de signature
- La vérification de signature est à temps constant
- L’horodatage est requis et vérifié avec une tolérance définie
- La protection contre le rejeu existe en utilisant un identifiant de livraison stable
- Le gestionnaire est idempotent au niveau de la couche d’effet de bord
- Les requêtes non vérifiées n’atteignent jamais les processeurs en aval
- Le contenu e-mail est traité comme une saisie non fiable (pas de rendu HTML, listes d’hôtes autorisés, extraction d’artefacts minimale)
Architecture de référence : webhook d’abord avec repli sur sondage
La livraison webhook est le moyen à latence la plus faible pour recevoir du courrier entrant, mais les systèmes de production devraient être résistants aux échecs de livraison occasionnels.
Un modèle courant dans les systèmes de boîte de réception d’automatisation d’abord est :
- Le webhook se déclenche rapidement quand un e-mail arrive.
- Votre gestionnaire vérifie l’authenticité, persiste un enregistrement, et met en file d’attente le travail.
- Si le webhook est manqué ou retardé, votre flux de travail peut sonder l’API de boîte de réception comme repli.
Mailhook supporte à la fois les notifications webhook et une API de sondage, ce qui est utile pour le QA déterministe et les flux de travail d’agent où vous voulez “pousser d’abord, tirer en secours”.

Notes pratiques pour les agents LLM : l’authenticité est nécessaire, pas suffisante
Même les webhooks parfaitement authentifiés peuvent livrer du contenu hostile, parce que les attaquants peuvent envoyer de vrais e-mails à vos boîtes de réception jetables.
Pour la sécurité de l’agent :
- Préférez une vue JSON minimisée (sujet, de, reçu_à, et artefact extrait), pas HTML brut.
- Évitez de laisser les agents “naviguer” sur des liens arbitraires trouvés dans l’e-mail.
- Ajoutez des listes d’hôtes autorisés pour les liens de vérification (et considérez résoudre les redirections côté serveur avec des règles strictes).
- Mettez des budgets stricts sur les actions d’agent (pas de boucles répétées “renvoyer le code”).
C’est là que la livraison JSON structurée aide : elle rend plus facile de construire des extracteurs déterministes et minimaux au lieu de scraping HTML fragile.
Exemple de pseudocode (structure, pas spécifique au fournisseur)
L’objectif est de montrer le flux de contrôle sans inventer de détails de fournisseur.
raw_body = getRawRequestBodyBytes(req)
sig = req.headers["Signature"]
timestamp = req.headers["Signature-Timestamp"]
if !sig or !timestamp:
return 401
if isTooOld(timestamp, toleranceSeconds=300):
return 401
expected = computeSignature(secret, timestamp, raw_body)
if !constantTimeEquals(sig, expected):
return 403
delivery_id = parseJson(raw_body).delivery_id
if seenRecently(delivery_id):
return 200 // acceptation idempotente
markSeen(delivery_id, ttl=24h)
enqueueForProcessing(raw_body)
return 200
Pour implémenter ceci correctement pour Mailhook (noms d’en-têtes réels, comment la chaîne signée est construite, et quels IDs sont disponibles), suivez le contrat dans mailhook.co/llms.txt.
Où Mailhook s’intègre (sans changer votre posture de sécurité)
Mailhook est conçu pour les flux de travail où l’e-mail est une entrée pour les systèmes logiciels, incluant les agents LLM et l’automatisation QA :
- Créer des boîtes de réception jetables via API
- Recevoir des e-mails entrants comme JSON structuré
- Obtenir des notifications webhook en temps réel (plus sondage comme repli)
- Vérifier l’authenticité avec des charges utiles webhook signées
- Utiliser des domaines partagés instantanément, ou apporter un domaine personnalisé quand vous avez besoin d’un contrôle plus serré
Si vous construisez un pipeline “e-mail comme flux d’événements”, le point clé à retenir est : traitez votre webhook comme une surface d’API publique. Vérifier “e-mail signé par” au niveau e-mail est utile, mais vérifier l’authenticité des charges utiles webhook est ce qui protège vos automatisations.
Pour les détails d’implémentation, exemples, et le contrat d’intégration canonique, commencez ici : Mailhook llms.txt.