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
- Captura el cuerpo crudo de la solicitud (bytes, antes de cualquier parsing JSON).
- Captura los encabezados
X-Infi-TimestampyX-Infi-Signature. - Concatena:
payload = "{timestamp}.{rawBody}". - Calcula
expected = HMAC-SHA256(WEBHOOK_SECRET, payload)y codifica en hex. - Compara
"sha256=" + expectedcon 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" ]]