Mercado Pago, la pasarela de pago más usada en América Latina y con fuerte presencia en España, firma cada notificación de webhook con HMAC-SHA256: el comercio recibe una clave secreta al configurar la integración, y cada notificación entrante trae una firma que hay que recalcular localmente y comparar con la recibida. Si no coincide, la notificación no viene realmente de Mercado Pago, y no debe procesarse como un pago real.
Por qué hace falta una clave secreta, no solo un hash
Un hash normal como SHA-256 solo demuestra que los datos no se corrompieron en tránsito, no quién los envió. Si un servidor simplemente hasheara el cuerpo del webhook y lo comparara con un hash incluido en la petición, un atacante podría fabricar su propia notificación falsa y adjuntar un hash que coincida. HMAC soluciona esto mezclando una clave secreta que solo conocen el emisor y el receptor: sin ella, generar una firma válida es inviable aunque el atacante conozca exactamente qué función hash se usa.
Por qué no es solo "hash de la clave más el mensaje"
Concatenar ingenuamente clave y mensaje antes de hashear (por ejemplo hash(clave + mensaje)) es vulnerable a ataques de extensión de longitud en algunas funciones hash: un atacante a veces puede añadir datos y calcular un nuevo hash válido sin conocer la clave completa. HMAC usa una construcción específica con doble hasheo y relleno interno/externo que cierra por completo esta clase de ataque.
Dónde más aparece HMAC
Además de firmar webhooks, HMAC autentica peticiones a APIs y es la pieza central del algoritmo TOTP, el que genera los códigos de seis dígitos de las aplicaciones autenticadoras.
Para qué se necesita esto
- Verificar la autenticidad de webhooks de pasarelas de pago u otros servicios de terceros.
- Firmar peticiones a APIs sin enviar nunca la clave secreta en sí por la red.
- Entender el funcionamiento interno de los códigos TOTP y los tokens de sesión.
Comparación en tiempo constante
Comparar la firma recibida con la esperada usando un === normal es inseguro: ese operador suele detenerse en el primer byte de discrepancia, y el tiempo de la comparación revela al atacante cuántos bytes iniciales adivinó correctamente. Un manejador de webhooks bien implementado siempre usa una función de comparación en tiempo constante — como hash_equals en PHP o crypto.timingSafeEqual en Node.js — que revisa todos los bytes sin importar dónde esté la primera discrepancia.