Localizzato tramite IA

Firma della Richiesta

Ogni richiesta webhook da Emailit include un header X-Emailit-Signature contenente una firma HMAC-SHA256 e un header X-Emailit-Timestamp con il timestamp Unix di quando la richiesta è stata firmata. È necessario verificare questa firma per assicurarsi che la richiesta sia autentica e non sia stata manomessa.

Come funziona

  1. Quando crei un webhook, Emailit genera un segreto di firma per quell'endpoint
  2. Per ogni consegna, Emailit concatena il timestamp e il corpo grezzo della richiesta come {timestamp}.{rawBody}
  3. Viene calcolato un hash HMAC-SHA256 su quella stringa utilizzando il tuo segreto di firma
  4. La firma viene inviata nell'header X-Emailit-Signature e il timestamp in X-Emailit-Timestamp
  5. Il tuo server ricalcola la firma e la confronta con il valore dell'header

Verifica della firma

Per verificare una firma webhook:

  1. Estrai gli header X-Emailit-Signature e X-Emailit-Timestamp dalla richiesta
  2. Concatena il timestamp e il corpo grezzo della richiesta come {timestamp}.{rawBody}
  3. Calcola un hash HMAC-SHA256 di quella stringa utilizzando il tuo segreto di firma webhook
  4. Confronta l'hash calcolato con la firma utilizzando un confronto sicuro temporalmente
  5. Opzionalmente, rifiuta le richieste dove il timestamp è più vecchio di alcuni minuti per proteggerti dagli attacchi replay

Verifica firma

import crypto from 'crypto';

function verifyWebhookSignature(rawBody, signature, timestamp, secret) {
  const signedPayload = `${timestamp}.${rawBody}`;
  const computed = crypto
    .createHmac('sha256', secret)
    .update(signedPayload, 'utf8')
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(computed, 'hex'),
    Buffer.from(signature, 'hex')
  );
}

// Nel tuo gestore webhook:
const rawBody = req.body; // corpo grezzo della richiesta come stringa
const signature = req.headers['x-emailit-signature'];
const timestamp = req.headers['x-emailit-timestamp'];
const secret = process.env.WEBHOOK_SIGNING_SECRET;

// Protezione contro attacchi replay (tolleranza di 5 minuti)
const age = Math.floor(Date.now() / 1000) - parseInt(timestamp, 10);
if (age > 300) {
  return res.status(401).send('Richiesta troppo vecchia');
}

if (!verifyWebhookSignature(rawBody, signature, timestamp, secret)) {
  return res.status(401).send('Firma non valida');
}

Note importanti

  • La firma viene calcolata su {timestamp}.{rawBody} — utilizza sempre la stringa del corpo grezzo della richiesta, non una versione ri-serializzata (ad es. JSON.stringify(req.body)). Differenze negli spazi bianchi o nell'ordinamento delle chiavi comprometteranno la firma.
  • Utilizza sempre una funzione di confronto sicuro temporalmente (ad es. crypto.timingSafeEqual, hmac.compare_digest, hash_equals) per prevenire attacchi temporali.
  • Considera di rifiutare le richieste dove l'X-Emailit-Timestamp è più vecchio di alcuni minuti per proteggerti dagli attacchi replay.
  • Mantieni sicuro il tuo segreto di firma — conservalo nelle variabili d'ambiente, non nel codice sorgente.
  • Puoi trovare il tuo segreto di firma webhook nella dashboard di Emailit sotto le impostazioni webhook, o tramite l'API Webhooks.