Ecossistema

HMAC / Webhooks

Utilitário e snippet para validar o header X-HyzePay-Signature (mesmo padrão Stripe).

Guia completo: Webhooks → Segurança.

Algoritmo

  1. Header: t=<unix>,v1=<hex>
  2. Mensagem: ${t}.${rawBody}
  3. HMAC_SHA256(secret, mensagem) em hex
  4. Rejeite se |now − t| > 300s
  5. Compare com timing-safe equal

Node.js

import { createHmac, timingSafeEqual } from "crypto";

export function verifyHyzePaySignature(opts: {
  secret: string;
  rawBody: string;
  signatureHeader: string;
  toleranceSec?: number;
}): boolean {
  const tolerance = opts.toleranceSec ?? 300;
  const parts = opts.signatureHeader.split(",").map((p) => p.trim());
  let t: number | null = null;
  const signatures: string[] = [];
  for (const part of parts) {
    const [k, v] = part.split("=");
    if (k === "t" && v) t = Number(v);
    if (k === "v1" && v) signatures.push(v);
  }
  if (t == null || !signatures.length) return false;
  if (Math.abs(Math.floor(Date.now() / 1000) - t) > tolerance) return false;

  const expected = createHmac("sha256", opts.secret)
    .update(`${t}.${opts.rawBody}`, "utf8")
    .digest("hex");
  const expectedBuf = Buffer.from(expected, "utf8");
  return signatures.some((sig) => {
    try {
      const got = Buffer.from(sig, "utf8");
      return got.length === expectedBuf.length && timingSafeEqual(got, expectedBuf);
    } catch {
      return false;
    }
  });
}

Via CLI

hyzepay webhooks verify \
  --secret whsec_… \
  --signature 't=…,v1=…' \
  --body-file payload.json