X-Wabox-Signature, calculado com o segredo da instância sobre o corpo cru da requisição:
t— timestamp Unix (segundos) de quando o Wabox assinou.v1—HMAC-SHA256(secret, "<t>.<corpo cru>")em hexadecimal.
whsec_…) aparece no painel em Webhooks e configurações gerais e em GET /webhooks (campo secret). Cada instância tem o seu.
Verificação
1
Leia o corpo cru
A assinatura é sobre os bytes exatos que chegaram. Se o seu framework já converteu o JSON em objeto, re-serializar não reproduz o mesmo texto. Capture o corpo antes do parser (
express.raw, request.body() no FastAPI, php://input).2
Recalcule e compare em tempo constante
Monte
"<t>.<corpo>", calcule o HMAC-SHA256 com o segredo e compare com v1 usando comparação de tempo constante.3
Rejeite timestamps antigos
Descarte entregas com
t a mais de 5 minutos do relógio atual. Isso limita ataques de repetição com um corpo capturado.Rotação do segredo
POST /webhooks/secret gera um segredo novo e devolve o valor. Entregas já enfileiradas continuam assinadas com o segredo anterior até esgotarem as tentativas; aceite os dois por algumas horas durante a troca. Hoje o header traz um único v1=; escreva o verificador aceitando vários, separados por vírgula, para não quebrar se isso mudar.
Quando não há assinatura
Toda instância nasce com um segredo. SeGET /webhooks devolver secret: null (instâncias antigas), as entregas chegam sem o header: gere um segredo com POST /webhooks/secret e passe a exigir a assinatura no seu endpoint.
Outras defesas
- Use HTTPS na URL do webhook. HTTP é aceito para testes, mas expõe o conteúdo das mensagens no caminho.
- Trate
event_idcomo chave de idempotência: entregas podem repetir. - Não confie em
instance_iddo corpo para autorizar: use a assinatura da instância correspondente.