Guias
Validando assinatura HMAC
Compare a assinatura do corpo recebido com HMAC-SHA256.
#Como validar
Leia o corpo bruto. Calcule HMAC-SHA256 hexadecimal com a secret key e compare em tempo constante com X-Signature-256 ou X-Webhook-Signature.
#Exemplo no servidor
server.mjs
import { createHmac, timingSafeEqual } from "node:crypto";
import { createServer } from "node:http";
const secret = process.env.GRANDEPAY_SECRET_KEY;
if (!secret) {
throw new Error("Defina GRANDEPAY_SECRET_KEY no servidor.");
}
function readRawBody(req) {
return new Promise((resolve, reject) => {
const chunks = [];
req.on("data", (chunk) => chunks.push(chunk));
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
req.on("error", reject);
});
}
function signaturesMatch(received, expected) {
const receivedBuffer = Buffer.from(received);
const expectedBuffer = Buffer.from(expected);
if (receivedBuffer.length !== expectedBuffer.length) {
return false;
}
return timingSafeEqual(receivedBuffer, expectedBuffer);
}
createServer(async (req, res) => {
const rawBody = await readRawBody(req);
const header =
req.headers["x-signature-256"] || req.headers["x-webhook-signature"] || "";
const expected = createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
if (!signaturesMatch(String(header), expected)) {
res.writeHead(401);
res.end();
return;
}
res.writeHead(204);
res.end();
}).listen(3001);#Fixture de teste
Corpo {"event":"transaction.paid","timestamp":"2026-03-13T17:05:32.000Z","data":{"id":"4d78d8ca-a9f1-4c2a-bf15-7f8ca71e3a70","amount_cents":1500}}, segredo sk_docs_fixture_do_not_use, digest ed7d4198d1227586c7ea8ad136d58eb42aabe8dec3157ace1686175b3dece78e. O digest bate no corpo original e falha se um byte do JSON ou o segredo mudam.
Esta página foi útil?