最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

node.js - Authorize.Net Webhook - Stack Overflow

programmeradmin1浏览0评论

I am working with Nodejs and I want invoice to status to updated by net.authorize.payment.authcapture.created event. Payment is successful but the webhook signature I get Invalid HMAC signature. HMAC do not match

[0] Webhook Request Headers: {
[0]   host: 'f273-97-64-131-130.ngrok-free.app',
[0]   'content-length': '438',
[0]   'content-type': 'application/json',
[0]   expect: '100-continue',
[0]   'x-anet-signature': 'sha512=72A339F0FA63917346CAD6C5EFD84F20321BB1177459024C2A56B9602D1573D66BD27BEE09858843FEA80885C6BE3F0AA2A5A3C866D9261FE72774F87BCD7031',
[0]   'x-forwarded-for': '198.241.206.38',
[0]   'x-forwarded-host': 'f273-97-64-131-130.ngrok-free.app',
[0]   'x-forwarded-proto': 'https',
[0]   'x-opnet-transaction-trace': '9903cec4-6192-4042-9bce-b5b44bd782f2-11088-50965',
[0]   'accept-encoding': 'gzip'
[0] }
[0] Payload for HMAC: {"notificationId":"43396377-04b6-4c52-bb7f-5209d6376daa","eventType":"net.authorize.payment.authcapture.created","eventDate":"2025-02-06T04:38:23.3448159Z","webhookId":"d516f763-b101-459d-abed-3acbd836965a","payload":{"responseCode":1,"authCode":"MQ3APZ","avsResponse":"Y","authAmount":4000,"fraudList":[{"fraudFilter":"Amount Filter","fraudAction":"report"}],"invoiceNumber":"2025-0030","entityName":"transaction","id":"80037536431"}}
[0] Received HMAC: 72A339F0FA63917346CAD6C5EFD84F20321BB1177459024C2A56B9602D1573D66BD27BEE09858843FEA80885C6BE3F0AA2A5A3C866D9261FE72774F87BCD7031
[0] Computed HMAC: ca0e7c4e74390d805cf271dabc0e7aa7e58cd9635946c1ea654363bd87839347ba63290400ea6fd9ad95ea09a04c7a697b5448ca1aa073c3889d84281cc71bf4
[0] Computed HMAC Length: 128
[0] Received HMAC Length: 128
[0] Invalid HMAC signature.

I have tried testing using postman and ngrok and still can't get it to work. I have created several signature keys in authorize sandbox but still getting Invalid HMAC signature. Here is the result I get from payload

const verifyHMAC = (payload, receivedHMAC) => {
      if (!receivedHMAC) {
        console.error("Received HMAC is missing.");
        return false;
      } 

      const signatureWithoutPrefix = receivedHMAC.split("=")[1]?.trim();
      if (!signatureWithoutPrefix) {
        console.error("Invalid HMAC format received.");
        return false;
      }

      console.log("Payload for HMAC:", JSON.stringify(payload));

      const hmac = crypto.createHmac(
        "sha512",
        Buffer.from(process.env.AUTHORIZE_NET_SIGNATURE_KEY, "hex")
      );
      hmac.update(JSON.stringify(payload));
      const computedHMAC = hmac.digest("hex");

      console.log("Received HMAC:", signatureWithoutPrefix);
      console.log("Computed HMAC:", computedHMAC);
      console.log("Computed HMAC Length:", computedHMAC.length);
      console.log("Received HMAC Length:", signatureWithoutPrefix.length);

      if (computedHMAC.length !== signatureWithoutPrefix.length) {
        console.error("Computed and received HMAC lengths do not match.");
        return false; // No comparison happens if lengths are different
       }

      return crypto.timingSafeEqual(
        Buffer.from(computedHMAC, "hex"),
        Buffer.from(signatureWithoutPrefix, "hex")
      );};

I am working with Nodejs and I want invoice to status to updated by net.authorize.payment.authcapture.created event. Payment is successful but the webhook signature I get Invalid HMAC signature. HMAC do not match

[0] Webhook Request Headers: {
[0]   host: 'f273-97-64-131-130.ngrok-free.app',
[0]   'content-length': '438',
[0]   'content-type': 'application/json',
[0]   expect: '100-continue',
[0]   'x-anet-signature': 'sha512=72A339F0FA63917346CAD6C5EFD84F20321BB1177459024C2A56B9602D1573D66BD27BEE09858843FEA80885C6BE3F0AA2A5A3C866D9261FE72774F87BCD7031',
[0]   'x-forwarded-for': '198.241.206.38',
[0]   'x-forwarded-host': 'f273-97-64-131-130.ngrok-free.app',
[0]   'x-forwarded-proto': 'https',
[0]   'x-opnet-transaction-trace': '9903cec4-6192-4042-9bce-b5b44bd782f2-11088-50965',
[0]   'accept-encoding': 'gzip'
[0] }
[0] Payload for HMAC: {"notificationId":"43396377-04b6-4c52-bb7f-5209d6376daa","eventType":"net.authorize.payment.authcapture.created","eventDate":"2025-02-06T04:38:23.3448159Z","webhookId":"d516f763-b101-459d-abed-3acbd836965a","payload":{"responseCode":1,"authCode":"MQ3APZ","avsResponse":"Y","authAmount":4000,"fraudList":[{"fraudFilter":"Amount Filter","fraudAction":"report"}],"invoiceNumber":"2025-0030","entityName":"transaction","id":"80037536431"}}
[0] Received HMAC: 72A339F0FA63917346CAD6C5EFD84F20321BB1177459024C2A56B9602D1573D66BD27BEE09858843FEA80885C6BE3F0AA2A5A3C866D9261FE72774F87BCD7031
[0] Computed HMAC: ca0e7c4e74390d805cf271dabc0e7aa7e58cd9635946c1ea654363bd87839347ba63290400ea6fd9ad95ea09a04c7a697b5448ca1aa073c3889d84281cc71bf4
[0] Computed HMAC Length: 128
[0] Received HMAC Length: 128
[0] Invalid HMAC signature.

I have tried testing using postman and ngrok and still can't get it to work. I have created several signature keys in authorize.net sandbox but still getting Invalid HMAC signature. Here is the result I get from payload

const verifyHMAC = (payload, receivedHMAC) => {
      if (!receivedHMAC) {
        console.error("Received HMAC is missing.");
        return false;
      } 

      const signatureWithoutPrefix = receivedHMAC.split("=")[1]?.trim();
      if (!signatureWithoutPrefix) {
        console.error("Invalid HMAC format received.");
        return false;
      }

      console.log("Payload for HMAC:", JSON.stringify(payload));

      const hmac = crypto.createHmac(
        "sha512",
        Buffer.from(process.env.AUTHORIZE_NET_SIGNATURE_KEY, "hex")
      );
      hmac.update(JSON.stringify(payload));
      const computedHMAC = hmac.digest("hex");

      console.log("Received HMAC:", signatureWithoutPrefix);
      console.log("Computed HMAC:", computedHMAC);
      console.log("Computed HMAC Length:", computedHMAC.length);
      console.log("Received HMAC Length:", signatureWithoutPrefix.length);

      if (computedHMAC.length !== signatureWithoutPrefix.length) {
        console.error("Computed and received HMAC lengths do not match.");
        return false; // No comparison happens if lengths are different
       }

      return crypto.timingSafeEqual(
        Buffer.from(computedHMAC, "hex"),
        Buffer.from(signatureWithoutPrefix, "hex")
      );};
Share Improve this question asked Feb 6 at 5:12 John AcheroJohn Achero 211 bronze badge 2
  • I think your payload was modified or something, for this kind of check you need to use raw body – Yuvaraj M Commented Feb 6 at 5:22
  • Also raw body does not needs to stringify – Yuvaraj M Commented Feb 6 at 5:23
Add a comment  | 

1 Answer 1

Reset to default 3

You should use raw request body (payload) in order to verify the signature.

Also I see a vulnerability in your code, You need to compare the whole string not Signature length.

const computedHMAC = crypto.createHmac(
  "sha512",
  Buffer.from(process.env.AUTHORIZE_NET_SIGNATURE_KEY, "hex")
).update(rawBody).digest("hex"); // here you need to user rawBody

console.log("Received HMAC:", signatureWithoutPrefix);
console.log("Computed HMAC:", computedHMAC);
console.log("Computed HMAC Length:", computedHMAC.length);
console.log("Received HMAC Length:", signatureWithoutPrefix.length);

if (computedHMAC !== signatureWithoutPrefix) { // compare the whole string 
  console.error("Computed and received HMAC lengths do not match.");
  return false; // No comparison happens if lengths are different
}
发布评论

评论列表(0)

  1. 暂无评论