¿Qué es la falsificación de webhooks (y por qué pasa)?
La falsificación de webhooks es cuando un atacante envía solicitudes falsas a tus endpoints “/webhooks/…” haciéndose pasar por el proveedor (pasarela de pago, Git, chat, etc.) para disparar acciones o robar datos.
Tu endpoint /webhooks/… es público. Cualquiera puede llamarlo. La única ‘identidad’ real es la firma y su frescura. Aquí te dejo cómo verificarla (con código), detectar replay y endurecer el endpoint sin afectar proveedores.
Solicita un pentest focalizado de webhooks:
pruebas técnicas + informe ejecutivo para gerencia.
El guion del atacante (qué hacen en la vida real).
- Descubre el endpoint: revisa documentación, repositorios y logs; enumera rutas con Burp/DirBuster.
- Clona el payload: copia un ejemplo público o intercepta uno real sin alterar orden ni codificación.
- Imita señales blandas: finge User-Agent, Content-Type e incluso IP “parecida” para saltar filtros débiles.
- Burla la verificación: aprovecha firma/timestamp mal validados o inexistentes.
- No se valida HMAC/clave pública contra el cuerpo crudo.
- Se aceptan algoritmos no permitidos o timestamps fuera de ventana.
- No hay antireplay: reenvía el mismo event-id/Idempotency-Key.
- Gatilla efectos: crea/activa usuarios, marca pagos como aprobados, dispara procesos o exfiltra datos.
Moraleja: ni HTTPS ni allowlists de IP prueban identidad. La diferencia entre proveedor real y atacante la marcan firma válida + frescura (timestamp) + antireplay, más validación de esquema y límites.
Agenda un “Webhook Health Check”:
validamos firmas, antireplay e idempotencia en 30 min.
Señales rojas (telemetría que debe encender alarmas)
- IP fuera de rango del proveedor: solicitud desde redes no publicadas o ASN inesperado → bloquea y registra ASN/IP.
- Timestamp fuera de ventana: fecha muy antigua o a futuro (±5 min) → responde 400 stale y registra desfase.
- Firma inválida o ausente: cabeceras vacías, algoritmo no permitido, firma que no cuadra con el cuerpo crudo → 401 bad signature.
- Replay detectado: Idempotency-Key o event-id repetido en corto tiempo → 409 replay y agrega a denylist temporal.
- Burst anómalo: picos de tráfico hacia un endpoint específico o fuera del patrón habitual → 429 + backoff y alerta al equipo.
- Esquema no coincide: tipo de evento declarado no corresponde al payload (campos faltantes/extras) → 422 unprocessable y traza el evento.
- Mide siempre: firmas fallidas, replays, p95/p99 de latencia y tasa de 4xx/5xx por webhook.
- Log mínimo por evento: event-id, digest, timestamp, resultado, IP/ASN, UA, latencia.
Cómo se defiende (lo que de verdad funciona)
A. Verificación criptográfica obligatoria
- Firma requerida: HMAC (secreto compartido) o firma asimétrica (clave pública del proveedor). Sin firma = 401.
- Qué verificar exactamente: cabecera de firma + timestamp + cuerpo crudo (sin re-serializar).
- Algoritmos permitidos: HMAC-SHA256, Ed25519, RSA-SHA256 (bloquea SHA-1 y lo que no esté en allowlist).
- Respuesta esperada:
- Firma inválida/ausente → 401 Bad Signature
- Algoritmo no permitido → 400 Unsupported Algorithm
- Cabeceras típicas: Stripe-Signature, X-Hub-Signature-256, X-Signature, X-Timestamp.
Do: recalcular con el mismo byte stream recibido.
Don’t: firmar/verificar el JSON parseado.
B. Antireplay
- Ventana de tiempo: tolerancia ±5 min entre now y el timestamp firmado.
- Memoria de eventos: guarda event-id / Idempotency-Key (o hash del body+ts) 10–30 min.
- One-and-done: un idempotency key/event-id se usa una vez; repetición = replay.
- Respuesta esperada:
- Timestamp fuera de ventana → 400 Stale
- Evento repetido → 409 Replay Detected (añade a denylist temporal)
C. Hardening del endpoint
- Solo POST con Content-Type esperado.
- Ruta fija y secreta (no “/webhook” genérico).
- Schema validation (JSON Schema/Protobuf).
- Rate limit por proveedor; 429 + backoff.
- mTLS opcional en B2B, si ambos lados lo soportan.
- Rotación de secretos y claves públicas cacheadas con TTL.
D. Observabilidad
- Log de (event-id, digest, ts, resultado, latencia, ip, UA).
- Métricas: tasa de verificación fallida, replays, % latencia p95/p99, 5xx.
Agenda un “Webhook Health Check”:
validamos firmas, antireplay e idempotencia en 30 min.
Errores que veo a diario (y rompen integraciones)
- Confiar solo en IP allowlist (CDN/proxies cambian rangos).
- Leer el body parseado para firmar (pierdes bytes exactos).
- Aceptar cualquier algoritmo declarado por el cliente.
- No tener idempotencia: reintentos duplican efectos.
- “2xx siempre” para no romper al proveedor (esconde fallos reales).
Plantilla de runbook (incidente por falsificación)
- Bloquea endpoint (WAF / feature flag).
- Revoca secretos del webhook y rota claves.
- Habilita antireplay (cache de eventos) si no estaba activo.
- Reprocesa eventos legítimos desde la bitácora del proveedor.
- Post-mortem con métricas y pruebas automáticas.
Revisamos tus endpoints de webhook, configuramos firma + antireplay y te dejo una prueba automatizada lista.
Suscríbete a Nuestro Blog: Mantente actualizado con las últimas noticias y consejos en ciberseguridad. Suscríbete ahora.
