Shopify HMAC验证在Webhook实现中失败。

huangapple go评论80阅读模式
英文:

Shopify HMAC verification failing in webhook implementation

问题

我正在开发一个Shopify应用程序。我试图使用这个函数来验证在应用程序上发生的Shopify交易,使用Shopify的HMAC身份验证验证。Webhook是通过Shopify Webhook API创建的,主题是app_subscriptions/update,shopifyApiSecret是我们的Shopify应用程序的客户端密钥。这是我们正在使用的代码片段,

async function validateHmac(req: Request) {
  let shopifyApiSecret = config.shopifyAppSecret;

  let hmac: any = req.headers["x-shopify-hmac-sha256"];
  const message = JSON.stringify(req.body);
  const generatedHash = crypto
    .createHmac("sha256", shopifyApiSecret)
    .update(message)
    .digest("base64");
  console.log({ message, generatedHash, hmac });

  const signatureOk = crypto.timingSafeEqual(
    Buffer.from(generatedHash),
    Buffer.from(hmac)
  );
  if (signatureOk) {
    return true;
  } else {
    return false;
  }
}

我们尝试了两种比较方式,即使用===和使用timingSafeEqual,但该函数始终返回false,检查时生成的哈希和hmac不相等。有人可以告诉我这个实现是否有任何问题吗?提前谢谢。

英文:

I'm working on developing a Shopify app. I'm trying to verify the Shopify transaction that happened on the app using Shopify's HMAC authentication verification using this function. The webhook is created through the Shopify Webhook API for the topic app_subscriptions/update and shopifyApiSecret is the Client Secret for our Shopify app. Here's the snippet of the code we're using,

async function validateHmac(req: Request) {
  let shopifyApiSecret = config.shopifyAppSecret;

  let hmac: any = req.headers["x-shopify-hmac-sha256"];
  const message = JSON.stringify(req.body);
  const generatedHash = crypto
    .createHmac("sha256", shopifyApiSecret)
    .update(message)
    .digest("base64");
  console.log({ message, generatedHash, hmac });

  const signatureOk = crypto.timingSafeEqual(
    Buffer.from(generatedHash),
    Buffer.from(hmac)
  );
  if (signatureOk) {
    return true;
  } else {
    return false;
  }
}

We've tried comparing both the ways, that is with === as well as using timingSafeEqual, but the function always returns false and the generatedHash and hmac are not equal on inspection. Can anyone let me know if there is anything wrong with this implementation? Thanks in advance.

答案1

得分: 0

以下是我们在.NET中完成的实现。您可以从以下代码理解逻辑:

string hmacHeader = Convert.ToString(Request.Headers["X-Shopify-Hmac-SHA256"]);
string requestJson = JsonSerializer.Serialize(request);

HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(APISecretKey));
string hash = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(requestJson)));

isSuccess = string.Equals(hmacHeader, hash, StringComparison.OrdinalIgnoreCase);
英文:

Here is the implementation we have done in .Net. You can understand the logic from below code:

string hmacHeader = Convert.ToString(Request.Headers["X-Shopify-Hmac-SHA256"]);
string requestJson = JsonSerializer.Serialize(request);

HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(APISecretKey));
string hash = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(requestJson)));

isSuccess = string.Equals(hmacHeader, hash, StringComparison.OrdinalIgnoreCase);

答案2

得分: 0

问题出在我们用于生成消息的数据上。
我们通过在路由中使用express函数来解决了这个问题。

express.json({
  limit: '10mb',
  verify: (req, _res, buf) => {
    (req as any).rawBody = buf;
  },
});

然后将rawBody传递给更新函数。

async function validateHmac(req: Request) {
  let shopifyApiSecret = config.shopifyAppSecret;

  let hmac: any = req.headers["x-shopify-hmac-sha256"];
  const message = req.rawBody;
  const generatedHash = crypto
    .createHmac("sha256", shopifyApiSecret)
    .update(message)
    .digest("base64");
  console.log({ message, generatedHash, hmac });

  const signatureOk = crypto.timingSafeEqual(
    Buffer.from(generatedHash),
    Buffer.from(hmac)
  );
  if (signatureOk) {
    return true;
  } else {
    return false;
  }
}
英文:

The issue was with the data we were consuming to generate the message.
We were able to solve it by using the express function in our router

express.json({
  limit: '10mb',
  verify: (req, _res, buf) => {
    (req as any).rawBody = buf;
  },
});

and passing the rawBody to the update function.

async function validateHmac(req: Request) {
  let shopifyApiSecret = config.shopifyAppSecret;

  let hmac: any = req.headers["x-shopify-hmac-sha256"];
  const message = req.rawBody;
  const generatedHash = crypto
    .createHmac("sha256", shopifyApiSecret)
    .update(message)
    .digest("base64");
  console.log({ message, generatedHash, hmac });

  const signatureOk = crypto.timingSafeEqual(
    Buffer.from(generatedHash),
    Buffer.from(hmac)
  );
  if (signatureOk) {
    return true;
  } else {
    return false;
  }
}

huangapple
  • 本文由 发表于 2023年6月12日 18:38:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76455820.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定