Pular para o conteúdo

Validar assinaturas de webhook

O segredo do webhook é exibido uma única vez quando um diretor da imobiliária cria ou regenera a configuração. Armazene-o em um gerenciador de segredos.

Para cada requisição:

  1. Leia Webhook-Timestamp e rejeite horários fora da tolerância definida por sua integração.
  2. Preserve o corpo da requisição como bytes brutos.
  3. Calcule o HMAC-SHA256 de <timestamp>.<corpo bruto> usando o segredo do webhook.
  4. Adicione v1= antes do resumo hexadecimal em letras minúsculas.
  5. Compare o resultado com Webhook-Signature em tempo constante.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyWebhookSignature({ rawBody, timestamp, signature, secret }) {
const expected = `v1=${createHmac('sha256', secret)
.update(timestamp)
.update('.')
.update(rawBody)
.digest('hex')}`;
const received = Buffer.from(signature, 'utf8');
const calculated = Buffer.from(expected, 'utf8');
return received.length === calculated.length && timingSafeEqual(received, calculated);
}
var mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
mac.update(timestamp.getBytes(StandardCharsets.UTF_8));
mac.update((byte) '.');
var digest = mac.doFinal(rawBody);
var expected = "v1=" + HexFormat.of().formatHex(digest);
var valid = MessageDigest.isEqual(
expected.getBytes(StandardCharsets.UTF_8),
signature.getBytes(StandardCharsets.UTF_8));

Não interprete e serialize novamente o JSON antes da validação. Diferenças de espaços, caracteres de escape ou ordem das propriedades alteram a assinatura.