# Sécuriser un webhook Brevo consommé par un rebuild Vercel

> Vérifier la signature d'un événement Brevo avant de déclencher un rebuild de site statique, pour éviter qu'un rebuild forgé ne soit déclenché par un tiers malveillant.

- Auteur : WordPress Développement
- Publié le : 2023-06-16
- Mis à jour le : 2023-06-16
- Catégorie : Headless &amp; API
- URL : https://www.wpmoderne.fr/headless/securiser-webhook-brevo-rebuild-vercel/

## L’essentiel

- Un endpoint de déclenchement de rebuild sans vérification de signature peut être appelé par n'importe qui
- Brevo signe ses webhooks, et cette signature doit être vérifiée avant tout traitement
- Un rebuild forgé et répété peut épuiser le quota de build d'un hébergeur en quelques minutes

`POST /api/rebuild-hook` : un endpoint aussi simple que celui-ci, sans aucune vérification, peut être appelé par n'importe qui capable de deviner son URL. Sur un site vitrine alimenté par des campagnes d'emailing Brevo dont le contenu déclenchait un rebuild statique Vercel à chaque mise à jour d'un modèle de newsletter, cette porte ouverte n'a été identifiée qu'après un audit de sécurité de routine, avant qu'elle ne soit exploitée.

Un attaquant capable d'appeler cet endpoint à répétition aurait pu épuiser en quelques minutes le quota de builds mensuel de l'hébergeur, provoquant un déni de service indirect sans même avoir besoin de compromettre quoi que ce soit côté WordPress ou Brevo. La correction a consisté à vérifier systématiquement la signature du webhook avant de déclencher le moindre rebuild.

## Le problème : un endpoint public sans validation

L'endpoint de rebuild, une simple fonction serverless Vercel, se contentait de recevoir une requête POST et de relayer un appel vers l'API de déploiement Vercel dès réception, sans se soucier de vérifier que l'appelant était réellement Brevo :

```
// Version initiale, non sécurisée
export default async function handler(req, res) {
  await fetch(process.env.VERCEL_DEPLOY_HOOK_URL, { method: 'POST' });
  res.status(200).json({ ok: true });
}
```

N'importe quelle requête POST vers cette URL, connue ou devinée, déclenchait un rebuild complet du site, indépendamment de sa provenance réelle.

## Vérifier la signature avant tout traitement

Brevo transmet, selon la configuration du webhook, un en-tête personnalisé permettant de vérifier l'authenticité de l'appel. La pratique retenue consiste à définir, côté configuration du webhook Brevo, un jeton secret partagé, transmis dans un en-tête personnalisé, puis à le comparer côté serveur avant tout traitement :

> L'essentiel à retenir : Un endpoint de déclenchement de rebuild sans vérification de signature peut être appelé par n'importe qui ; Brevo signe ses webhooks, et cette signature doit être vérifiée avant tout traitement ; Un rebuild forgé et répété peut épuiser le quota de build d'un hébergeur en quelques minutes

```
export default async function handler(req, res) {
  const secretRecu = req.headers['x-brevo-secret'];

  if (secretRecu !== process.env.BREVO_WEBHOOK_SECRET) {
    return res.status(401).json({ erreur: 'signature invalide' });
  }

  await fetch(process.env.VERCEL_DEPLOY_HOOK_URL, { method: 'POST' });
  res.status(200).json({ ok: true });
}
```

Cette vérification, volontairement simple, repose sur une comparaison directe de chaîne. Pour un usage plus exigeant, une comparaison à temps constant (via `crypto.timingSafeEqual` en Node.js) évite en plus les attaques par mesure de temps de réponse, bien que le risque reste marginal pour ce cas d'usage précis.

## Limiter la fréquence des rebuilds

Même avec une signature valide, un événement Brevo légitime mais répété rapidement (plusieurs campagnes modifiées coup sur coup) peut déclencher une rafale de rebuilds inutiles. Une limitation de fréquence, stockée dans une base clé-valeur légère, empêche plus d'un rebuild toutes les cinq minutes :

```
const dernierRebuild = await kv.get('dernier_rebuild_brevo');
const maintenant = Date.now();

if (dernierRebuild && maintenant - dernierRebuild < 5 * 60 * 1000) {
  return res.status(429).json({ erreur: 'rebuild déjà déclenché récemment' });
}

await kv.set('dernier_rebuild_brevo', maintenant);
```

## Journaliser chaque déclenchement

Chaque appel réussi à l'endpoint est désormais journalisé avec son horodatage et un identifiant d'événement Brevo si disponible, permettant de retracer a posteriori l'origine de chaque rebuild déclenché en cas de doute ou d'incident de production.

- Horodatage de la requête reçue
- Résultat de la vérification de signature (accepté ou rejeté)
- Identifiant du déploiement Vercel déclenché en retour

## Notre verdict

Un endpoint de déclenchement de rebuild sans vérification d'origine constitue une vulnérabilité aussi simple à exploiter qu'à corriger. La vérification de signature, associée à une limitation de fréquence, transforme un point d'entrée ouvert en un mécanisme fiable, sans jamais avoir eu besoin de toucher à la configuration des campagnes d'emailing elles-mêmes, qui reste un sujet totalement distinct.
