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áctica | Razón |
|---|---|
| Usa HTTPS en producción | Las firmas viajan en texto plano sobre HTTP |
| Usa timing-safe comparison | Previene ataques de timing |
Responde 200 OK inmediatamente | Procesa el evento de forma asíncrona |
| Implementa idempotencia | Usa el campo id del evento para deduplicar |
| Verifica el timestamp | Rechaza eventos más viejos que 5 minutos |
Reintentos
Si tu endpoint no responde 2xx en 10 segundos, OmniBuy reintenta con backoff exponencial:
| Intento | Delay |
|---|---|
| 1 | 1 min |
| 2 | 5 min |
| 3 | 30 min |
| 4 | 2 horas |
| 5 | 24 horas |
Después de 5 intentos fallidos, el evento se marca como failed.