Saltar al contenido principal

Seguridad de webhooks

Verificación de firma

Cada entrega incluye el header X-OmniBuy-Signature con una firma HMAC-SHA256 del payload.

Header format

X-OmniBuy-Signature: sha256=<hex-digest>

Verificación (Node.js)

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');

return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}

// En tu handler de Express:
app.post('/webhooks', (req, res) => {
const signature = req.headers['x-omnibuy-signature'];
const isValid = verifyWebhookSignature(
req.rawBody,
signature,
process.env.WEBHOOK_SECRET
);

if (!isValid) {
return res.status(401).send('Invalid signature');
}

// Procesar evento...
res.status(200).send('OK');
});

Verificación (Go)

import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"strings"
)

func VerifySignature(payload []byte, signature, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(payload)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expected))
}

Verificación (Python)

import hmac
import hashlib

def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)

Mejores prácticas

PrácticaRazón
Usa HTTPS en producciónLas firmas viajan en texto plano sobre HTTP
Usa timing-safe comparisonPreviene ataques de timing
Responde 200 OK inmediatamenteProcesa el evento de forma asíncrona
Implementa idempotenciaUsa el campo id del evento para deduplicar
Verifica el timestampRechaza eventos más viejos que 5 minutos

Reintentos

Si tu endpoint no responde 2xx en 10 segundos, OmniBuy reintenta con backoff exponencial:

IntentoDelay
11 min
25 min
330 min
42 horas
524 horas

Después de 5 intentos fallidos, el evento se marca como failed.