Verificación de la firma

Toda solicitud de webhook llega con:

  • X-Infi-Timestamp: timestamp unix en segundos.
  • X-Infi-Signature: sha256=<hex>, donde <hex> es el HMAC-SHA256 calculado sobre la concatenación "{timestamp}.{cuerpo crudo}" usando el secreto del webhook.

Algoritmo

  1. Captura el cuerpo crudo de la solicitud (bytes, antes de cualquier parsing JSON).
  2. Captura los encabezados X-Infi-Timestamp y X-Infi-Signature.
  3. Concatena: payload = "{timestamp}.{rawBody}".
  4. Calcula expected = HMAC-SHA256(WEBHOOK_SECRET, payload) y codifica en hex.
  5. Compara "sha256=" + expected con el encabezado recibido en tiempo constante.
Usa el cuerpo crudo, no JSON reserializado

La firma es sobre los bytes exactos enviados. Reserializar el JSON de tu lado puede cambiar el orden de claves o el espaciado y romper la verificación. Configura tu framework para preservar el body crudo (p.ej. en Express usa express.raw({ type: 'application/json' })).

Dónde obtener el `WEBHOOK_SECRET`

El secreto se entrega junto con tu API key, por el canal seguro acordado con INFI (correo cifrado o panel). No lo expongas en código fuente público ni en logs — guárdalo como variable de entorno.

Mitigación de replay

Recomendado: rechaza webhooks con X-Infi-Timestamp muy antiguo (p.ej. > 5 minutos). Esto protege contra replay de webhooks legítimos capturados en tránsito.

Ejemplos

# Validación shell — usualmente se delega al lenguaje de la aplicación.
# Concepto:
#   payload="${TIMESTAMP}.${RAW_BODY}"
#   expected=$(echo -n "$payload" | openssl dgst -sha256 -hmac "$INFI_WEBHOOK_SECRET" | awk '{print $2}')
#   [[ "sha256=$expected" == "$X_INFI_SIGNATURE" ]]