Verifying Webhook Signatures by Hand: HMAC-SHA256 and Why Yours Keeps Failing

Verify webhook signatures manually with HMAC-SHA256. Learn why your comparisons fail — raw body, key encoding, timing attacks. Step-by-step guide for GitHub,

viernes, 24 de julio de 2026 • 6 min read • Q2BSTUDIO Team

Errores comunes en la verificación de firmas webhook

Integrar webhooks en una aplicación es una práctica habitual cuando se necesita recibir notificaciones en tiempo real de servicios externos: pasarelas de pago, plataformas de CI/CD, redes sociales o cualquier API que emita eventos. Sin embargo, la seguridad de estos endpoints suele darse por sentada hasta que ocurre un fallo. Una firma HMAC-SHA256 mal validada puede provocar desde un pago duplicado hasta una brecha de seguridad. En este artículo aprenderás a verificar una firma de webhook manualmente, sin depender de librerías externas, y entenderás por qué cada detalle importa: el cuerpo crudo, la codificación de la clave, el tiempo de comparación y los timestamps anti-replay. Todo ello enmarcado en una arquitectura empresarial robusta como la que ofrece Q2BSTUDIO en sus soluciones de aplicaciones a medida y ciberseguridad.

La verificación de firmas de webhook no es opcional: es la única barrera que impide que un atacante inyecte eventos falsos en tu sistema. Cuando un proveedor firma el cuerpo de la petición con una clave secreta compartida, el receptor puede recomputar esa firma y compararla. Si coinciden, el mensaje es auténtico y no ha sido alterado en tránsito. Este mecanismo, basado en HMAC-SHA256, es el estándar de facto en la industria. Pero implementarlo correctamente requiere entender exactamente qué bytes se están firmando y cómo tratarlos en cada lenguaje o framework.

Para realizar una verificación manual, necesitas tres elementos: el cuerpo de la petición en crudo (raw body), la clave secreta compartida y el algoritmo HMAC-SHA256. El proveedor envía la firma en un header —por ejemplo, X-Hub-Signature-256 en GitHub, Stripe-Signature en Stripe o X-Shopify-Hmac-Sha256 en Shopify— y tú la recalculas con la misma entrada. La primera lección: nunca uses el cuerpo parseado. Frameworks como Express o Django convierten el JSON en un objeto, pero al hacer JSON.stringify(parsedObject) el orden de las claves puede cambiar, se eliminan espacios y se escapan caracteres Unicode. El resultado jamás será idéntico al cuerpo original. Por eso debes capturar el buffer de la petición antes de que cualquier middleware lo transforme. En Node.js con Express, puedes usar express.raw({ type: 'application/json' }) para que req.body sea un Buffer. Luego aplicas crypto.createHmac('sha256', secret).update(req.body).digest('hex') y comparas con el header (quitando el prefijo 'sha256=' si lo tiene). En otros lenguajes, como Python con Flask, se accede a request.get_data() para obtener los bytes sin procesar.

La segunda causa frecuente de error es la codificación de la clave secreta. La mayoría de proveedores esperan que la clave se pase como una cadena UTF-8. Pero algunos —especialmente en banca y pagos— entregan la clave en hexadecimal o base64. Si la tratas como caracteres literales en lugar de decodificarla a bytes, la firma generada será completamente diferente. Por ejemplo, si el proveedor te da 'a1b2c3' como hex, debes convertir eso a su valor binario (0xa1, 0xb2, 0xc3) antes de pasarlo a HMAC. Si lo concatenas como 'a1b2c3' en UTF-8, obtienes una secuencia distinta. Siempre revisa la documentación del proveedor para saber el formato exacto de la clave.

La tercera trampa es la comparación no constante en tiempo. Un simple === entre dos cadenas devuelve falso en cuanto encuentra el primer carácter diferente, lo que permite a un atacante medir el tiempo de respuesta y adivinar la firma carácter por carácter. Esto es un vector de ataque conocido (timing attack). La solución es usar una función de comparación constante, como crypto.timingSafeEqual en Node.js, hmac.compare_digest en Python o MessageDigest.isEqual en Java. En entornos donde no exista una función nativa, puedes implementar XOR acumulativo: recorres todos los bytes sin salir antes de tiempo y comparas el resultado. Implementar esta seguridad es parte de las buenas prácticas que Q2BSTUDIO aplica en sus proyectos de ciberseguridad.

Además del HMAC puro, algunos proveedores como Stripe añaden un timestamp al payload firmado. El header Stripe-Signature tiene el formato: t=1699999999,v1=5257a869e7... El cuerpo a firmar es la concatenación del timestamp, un punto y el cuerpo crudo (t + '.' + body). Esto permite verificar no solo la autenticidad sino también la frescura del mensaje. Debes comprobar que el timestamp está dentro de una ventana de tiempo aceptable (normalmente 5 minutos) para evitar ataques de replay. Si estás desarrollando tu propia API que emite webhooks, deberías adoptar este mismo patrón: firmar timestamp + body y rechazar peticiones con sellos antiguos. Es una capa extra que refuerza la integridad del sistema.

La verificación manual se vuelve indispensable en tres escenarios. Primero, durante la integración inicial: antes de confiar en tu código, prueba con un payload de ejemplo que el proveedor haya documentado (GitHub proporciona uno muy claro). Recalcula la firma a mano y compárala con la esperada. Si no coincide, el error está en tu implementación, no en el proveedor. Segundo, cuando un evento concreto falla en producción: accede al log de entregas del proveedor, obtén el cuerpo exacto que enviaron y el header de firma, y reprodúcelo localmente. Así sabrás si es un problema de codificación del cuerpo, de la clave o un error genuino del proveedor. Tercero, al rotar secretos: tras cambiar una clave compartida, verifica manualmente un evento real antes de poner la nueva clave en producción. Estos pasos ahorran horas de depuración.

En el contexto empresarial, la correcta gestión de webhooks se integra dentro de un ecosistema más amplio de aplicaciones a medida, inteligencia artificial, cloud computing y automatización. Q2BSTUDIO despliega soluciones que incluyen desde el desarrollo de backend con firma HMAC hasta la orquestación de eventos en AWS o Azure. Por ejemplo, cuando un webhook de pago es verificado, se puede disparar un proceso automatizado que actualice un panel de BI en Power BI o active un agente de IA para analizar el comportamiento del cliente. La firma no es solo un detalle técnico: es el primer eslabón de una cadena de confianza que permite a las empresas escalar sus operaciones sin exponer sus datos. Las arquitecturas cloud, ya sea en AWS con Lambda y API Gateway o en Azure con Functions y Event Grid, deben incorporar verificación de firmas en los endpoints expuestos a internet. Ignorarlo es dejar la puerta abierta.

Los agentes de IA generativa también se benefician de una recepción segura de eventos. Imagina un asistente virtual que reacciona a pedidos de compra: cada notificación de nuevo pedido debe ser verificada para evitar que un agente malicioso inyecte órdenes falsas. La combinación de webhooks firmados con IA permite construir sistemas autónomos y seguros. En Q2BSTUDIO trabajamos con frameworks de agentes que consumen eventos de fuentes externas, siempre con validación criptográfica.

Para resumir, la verificación manual de firmas HMAC-SHA256 se reduce a cuatro reglas: usar siempre el cuerpo crudo, comparar en tiempo constante, decodificar la clave según lo especificado y, si el proveedor lo soporta, comprobar el timestamp. Con estas reglas, tu endpoint de webhook dejará de confiar en extraños. Si estás diseñando una arquitectura empresarial que integre múltiples fuentes de eventos, considera que la implementación correcta de esta verificación es una competencia que separa un sistema seguro de uno vulnerable. En Q2BSTUDIO ayudamos a empresas de todos los tamaños a construir aplicaciones a medida con los más altos estándares de ciberseguridad, integrando cloud, IA y BI de forma coherente. No dejes que un error de validación arruine tu próxima integración: verifica siempre la firma, y si tienes dudas, recurre a expertos.

A BREAK?

Play for a moment before you go

OUR SERVICES

How we can help you

Do you have a project in mind?

Tell us your vision and we'll turn it into a software solution. Whatever the scope, we make your idea real.