Firmar el aviso de una multa: cómo se valida el origen

Una URL de webhook escucha en Internet y cualquiera puede enviarle un POST bien formado. La firma con secreto compartido permite comprobar quién emitió el mensaje, si se verifica sobre los bytes exactos.

Foto de Marco FerreiroMarco FerreiroAutor en multas.ar
4 min de lectura
Sobre de papel madera con sello de lacre rojo junto a una llave antigua sobre un escritorio de madera con luz natural.
Sobre de papel madera con sello de lacre rojo junto a una llave antigua sobre un escritorio de madera con luz natural.

Un webhook llega a una URL que escucha en Internet. Cualquier sistema que conozca esa dirección puede enviarle un POST con un JSON bien formado que diga “nueva infracción detectada”. Si el receptor procesa todo lo que parece legítimo, un tercero puede disparar alertas, cobranzas o cambios de estado sin tocar la fuente real.

La pregunta central es de origen: quién generó el aviso de la infracción, no desde qué dirección llegó ni qué formato tiene. La respuesta habitual es una firma: el emisor calcula un código de autenticación con un secreto compartido y lo envía en un encabezado; el receptor recalcula y compara antes de procesar.

Esa frase esconde varias decisiones: qué cubre la firma, sobre qué bytes se calcula y cómo se compara.

Qué prueba la firma sobre el origen

Una firma correcta demuestra dos cosas: que quien la generó conoce el secreto asociado a esa integración y que los componentes cubiertos llegaron como fueron firmados. Nada más.

No demuestra que el contenido sea verdadero: un emisor legítimo puede avisar de un acta que no existe. No demuestra que el mensaje sea nuevo: una captura puede reenviarse con su firma intacta, un problema que tratamos en la nota sobre firmas HTTP y replay. Y no decide qué efectos ejecutar: eso pertenece al contrato de negocio del consumidor.

Separar esas capas evita la conclusión más peligrosa: “la firma validó, entonces todo está bien”.

La dirección IP no es el origen

Filtrar por IP responde otra pregunta: desde qué red llegó el paquete, no qué sistema informó el acta. Las direcciones de salida cambian con la infraestructura del emisor, pueden compartirse entre servicios y un intermediario reenvía tráfico legítimo e ilegítimo por igual.

TLS tampoco alcanza por sí solo. En la dirección de un webhook, el certificado autentica al receptor frente a quien se conecta; no le dice al receptor quién es el emisor, salvo que ambos acuerden autenticación mutua. Un filtro de red suma defensa en profundidad; el origen se comprueba con la firma.

Los bytes exactos, antes de parsear

El error más frecuente no está en la criptografía sino en la materia prima. La firma se calculó sobre una secuencia de bytes; la verificación tiene que usar exactamente esa secuencia antes de interpretar el JSON.

Deserializar y volver a serializar puede cambiar espacios, orden de claves o representación de números sin cambiar el significado. RFC 8785 existe porque la serialización de JSON no es canónica: define un esquema para fijar los bytes cuando no queda alternativa. Para un webhook la alternativa sí existe: verificar sobre el cuerpo crudo y recién después parsear. Verificá qué expone tu framework: muchos parsean el cuerpo antes de entregarlo, y para recalcular la firma necesitás los bytes crudos.

Conviene además que la firma cubra lo que distingue al mensaje. RFC 9530 define campos de digest para vincular el cuerpo, y RFC 9421 describe cómo cubrir método y destino junto con ese digest, de modo que un cuerpo válido no pueda adjuntarse a otra ruta.

Un secreto por integración, ubicado por su identificador

Un secreto global convierte cualquier filtración en un incidente de todas las flotas. Cada integración —y cada ambiente— necesita su propio secreto, y el mensaje indica con un identificador de clave cuál corresponde usar.

El identificador ubica la clave; no decide el algoritmo. El receptor mantiene en su configuración la asociación entre clave, algoritmo y vigencia, y rechaza identificadores desconocidos. El código de autenticación habitual combina el secreto con una función de hash; las de la familia SHA-2 están especificadas en FIPS 180-4.

El secreto se entrega por un canal de configuración, nunca dentro del propio webhook, y no aparece en logs.

Comparación y orden de verificación

Comparar la firma recibida con la esperada también es parte del contrato. Una comparación que corta en el primer byte distinto puede filtrar, a través de los tiempos de respuesta, cuántos bytes iniciales coinciden. La práctica establecida es calcular siempre la firma esperada completa y compararla con una función de tiempo constante.

El rechazo debería ser uniforme: la misma respuesta para un encabezado ausente, una clave desconocida y una firma incorrecta. El detalle vive en los logs del receptor —identificador de clave, motivo, metadatos—, nunca el acta ni el valor esperado.

Antes de cargar un acta, el receptor verifica en orden:

  • que el encabezado de firma y el identificador de clave existen;
  • que la clave está vigente para esa integración y el algoritmo es el configurado;
  • que el digest del cuerpo coincide con los bytes recibidos;
  • que la firma valida sobre los componentes cubiertos, comparada en tiempo constante.

Recién entonces empieza el procesamiento, con sus propias defensas: ventana temporal, detección de repetidos e idempotencia, como describe la nota sobre webhooks de nuevas multas.

La propiedad que buscamos es acotada y comprobable: un POST que anuncia un acta falsa y viene de un tercero que no conoce el secreto no supera la verificación, y uno legítimo la supera aunque cambie la dirección de salida del emisor. El origen se demuestra con criptografía y configuración, no con la forma del mensaje.

Metodología

Alcance
Verificación del origen de webhooks firmados con secreto compartido en integraciones de infracciones; no cubre replay, orden de llegada ni idempotencia, tratados en notas relacionadas.
Unidad de análisis
Un mensaje de webhook recibido, sus bytes exactos, el identificador de clave y el resultado de la verificación de la firma.
Cobertura
Semántica de RFC 9421, RFC 9530, RFC 8785 y FIPS 180-4 consultados el 28 de agosto de 2026; el esquema concreto de cada proveedor puede diferir en encabezados y formato.

Limitaciones

  • La nota no define un perfil interoperable completo ni reemplaza el modelado de amenazas de cada integración.
  • Los nombres de encabezados y el formato de la firma varían entre proveedores; el orden de verificación descripto es un criterio general.
  • El almacenamiento, la rotación y la revocación del secreto exceden el alcance y dependen de la plataforma del receptor.

Fuentes

Preguntas frecuentes

¿Una firma válida garantiza que el webhook dice la verdad?

No. Prueba que el emisor conoce el secreto de esa integración y que los componentes cubiertos no cambiaron en el camino. El contenido puede ser erróneo y el mensaje puede ser una repetición; esas capas se controlan con otras verificaciones.

¿Alcanza con una lista de IPs permitidas para validar el origen?

No como mecanismo principal. La IP dice desde qué red llegó el paquete, puede cambiar con la infraestructura del emisor y compartirse entre servicios distintos. Puede sumarse como defensa adicional, pero el origen del mensaje se comprueba con la firma.

¿Por qué verificar sobre los bytes crudos y no sobre el JSON parseado?

Porque la firma se calculó sobre una secuencia exacta de bytes. Deserializar y volver a serializar puede cambiar espacios, orden de claves o representación de números sin cambiar el significado, y la verificación fallaría u obligaría a canonicalizar con reglas frágiles.

¿Qué respondo cuando la firma no valida?

Un rechazo uniforme, sin distinguir si faltó el encabezado, la clave es desconocida o la firma es incorrecta. El detalle se registra en los logs del receptor, sin payload ni secretos, y el mensaje no ejecuta ningún efecto.

Notas relacionadas