【问题标题】:PHP hash_hmac to JS HmacPHP hash_hmac 到 JS Hmac
【发布时间】:2021-06-11 18:15:50
【问题描述】:

我正在尝试验证 webhook 签名,我从 api2cart 的文档中获得了这个 PHP 代码,但我需要在 Javascript 中使用它。我试过但是我无法匹配签名和 HMAC 生成的值,更多详细信息 @987654322 @

要遵循的步骤:

  1. 收集所有以“X-Webhook-”开头的标头 // 我在标头中将其作为 x-webhook- 接收,不知道它是否会影响加密

  2. 从数组中移除“X-Webhook-Signature”。

  3. 按字母顺序对标题进行排序

  4. 将标头编码为 JSON。

  5. 连接字符串,JSON 标头字符串应该放在第一位

  6. 使用 HMAC SHA256 函数对结果字符串进行散列,输出原始二进制数据集为 true (raw_output = true)

使用您的 store_key 作为密钥来生成二进制签名

  1. 用 Base64 编码字符串

$headersForJson = [
'X-Webhook-Error-Code' => '0',
'X-Webhook-Action' => 'update',

'X-Webhook-Timestamp' => '1516291592',

'X-Webhook-Entity' => 'product',

'X-Webhook-Store-Id' => '1',

'X-Webhook-Signature' => 'SGVsbG8gd2l0aCBBUEkyQ2FydA==',

];

$signatureFromRequest = $headersForJson['X-Webhook-Signature'];

unset($headersForJson['X-Webhook-Signature']);

ksort($headersForJson);

$headers = json_encode($headersForJson);

$data = $headers . $params['raw_body'];

$generatedSignature = base64_encode(hash_hmac('sha256', $data, $storeKey, true));

 if (hash_equals($signatureFromRequest, $generatedSignature)) {
   return true;
 }

这是我所做的:

const signature = headers['x-webhook-signature'];
delete headers['x-webhook-signature'];
    // the header contained other keys I had to get keys starting with x-webhooks
    let xkeys = Object.keys(headers).filter(key => key.includes('x-webhook-')).sort();
    let xheaders = JSON.stringify(xkeys.reduce((res, key) => Object.assign(res, { [key]: headers[key] }), {}));
    let data = xheaders + rawBody


const generatedHash = createHmac('SHA256', "SecretKey")
            .update(data, 'utf-8')
            .digest('base64');


return generatedHash === signature

我在这里错过了什么?

【问题讨论】:

  • 你好,到今天你解决了吗?

标签: javascript php webhooks hmac hmacsha1


【解决方案1】:

您需要将标头数组键从例如 x-webhook-entity 转换为 X-Webhook-Entity

例如:

   let xheaders = JSON.stringify(
      xkeys.reduce((res, key) => Object.assign(
        res,
        { [key.split('-').map(s => s[0].toUpperCase() + s.slice(1)).join('-')]: headers[key] }),//format header key from x-webhook-entity to X-Webhook-Entity
        {}
      )
    );

带有 Pipedream 的完整代码:

const crypto = require('crypto');
const storeKey = '5d780e682fbdbd4d04411be86ccd4b30';
const signature = event.headers['x-webhook-signature'];

const headers = event.headers;
delete headers['x-webhook-signature'];

// the header contained other keys I had to get keys starting with x-webhooks
let xkeys = Object.keys(headers).filter(key => key.includes('x-webhook-')).sort();
let xheaders = JSON.stringify(
  xkeys.reduce((res, key) => Object.assign(
    res,
    { [key.split('-').map(s => s[0].toUpperCase() + s.slice(1)).join('-')]: headers[key] }),//format header key from x-webhook-entity to X-Webhook-Entity
    {}
  )
);

const data = xheaders + JSON.stringify(event.body);
const generatedHash = crypto.createHmac('SHA256', storeKey)
            .update(data, 'utf-8')
            .digest('base64');

console.log(signature);
console.log(generatedHash);

let status = 403;

if (signature === generatedHash) {
  status = 200;
}

const response = await $respond({
  status: status,
  immediate: true,
  headers: {},
  body: {"signature":signature, "generatedHash":generatedHash} 
})

return JSON.parse(response.config.data).response

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,我解决了:

    1. 标题必须大写
    2. body 必须是 JSON.stringify (req.body) 并且 req.body 必须是 JSON 对象,而不是文本(不是 raw_body)

    这对我有用:

    const validateRequest = (headers, body, storeKey) => {
      const webhookHeaders = {
        "X-Webhook-Action": headers["x-webhook-action"],
        "X-Webhook-Entity": headers["x-webhook-entity"],
        "X-Webhook-Error-Code": headers["x-webhook-error-code"],
        "X-Webhook-Store-Id": headers["x-webhook-store-id"],
        "X-Webhook-Timestamp": headers["x-webhook-timestamp"]
      };
    
      const signatureFromRequest = headers["x-webhook-signature"];
      const data = JSON.stringify(webhookHeaders) + JSON.stringify(body);
      const generatedSignature = crypto
        .createHmac("sha256", storeKey)
        .update(data)
        .digest("base64");
    
      return !!crypto.timingSafeEqual(
        Buffer.from(signatureFromRequest),
        Buffer.from(generatedSignature)
      );
    };
    

    你可以这样称呼它:

    const headers = {
      "x-webhook-entity": "product",
      "x-webhook-action": "update",
      "x-webhook-store-id": "0",
      "x-webhook-error-code": "0",
      "x-webhook-timestamp": "1635502511",
      "x-webhook-signature": "Ua1dtsDBi+37fEGr3mTHN7laZqLQpl+tEK02RDAg++0="
    };
    const body = { id: "28" };
    const storeKey = "ed58a22dfecb405a50ea3ea56979360d";
    const isValid = validateRequest(headers, body, storeKey);
    
    console.log(isValid ? "success" : "failed"); // success
    

    【讨论】:

      猜你喜欢
      • 2022-06-16
      • 2022-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多