PHP hash_hmac to JS Hmac



我正在尝试验证一个webhook签名,我有api2cart文档中的PHP代码,但我需要它在Javascript中。我试过了,但我无法匹配签名和HMAC生成的值,更多详细信息请点击

要遵循的步骤:

  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

我在这里错过了什么?

您需要将头数组键从例如x-webhook-entity转换为x-webhook-ntity

例如:

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

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

  1. 标题必须使用大写字母
  2. body必须是JSON.stringify(req.body(,req.body必须是JSON对象,而不是text(不是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

最新更新