我正在从woocommerce网站接收webhooks,并将其转换为nodejs/express应用程序。我试图验证webhook的签名以证明其真实性,但我计算的哈希值从未与woocommerce报告的钩子签名头中的签名对应。
这是我用来验证真实性的代码:
function verifySignature(signature, payload, key){
var computedSignature = crypto.createHmac("sha256", key).update(payload).digest('base64');
debug('computed signature: %s', computedSignature);
return computedSignature === signature;
}
正在使用以下参数调用此函数:
var signature = req.headers['x-wc-webhook-signature'];
verifySignature(signature, JSON.stringify(req.body), config.wooCommence.accounts.api[config.env].webhookSecret)
webhook的签名头将签名报告为beyov/zzmbmujkhauwaqxjx8yr6jrktpzqn9j267oo=。然而,上述操作的结果是S34YqftH1R8F4uH4Ya2BSM1rn0H9NiqEA2Nr7W1CWZs=
我在网络钩子上手动配置了秘密,正如您在上面的代码中看到的,相同的秘密也在Express应用程序中硬编码。因此,要么我使用错误的有效负载来计算签名,要么有其他可疑的东西阻止我验证这些签名。
如果有人能帮我解决这个问题,我将不胜感激。
对于使用node的人来说,这应该可以做到。
var processWebHookSignature = function (secret, body, signature) {
signatureComputed = crypto.createHmac('SHA256', secret).update(
new Buffer(JSON.stringify(body), 'utf8')).digest('base64');
return ( signatureComputed === signature ) ? true : false;
}
这是个老问题,但也许它能帮助一些可怜的人。签名需要根据正文而不是它包含的JSON进行检查。i、 e.正文的原始字节。
伪:
byte[] body = request.Body;
string signature = request.Header["X-WC-Webhook-Signature"];
byte[] secretUtf8 = GetUtf8Bytes("yoursecrethere");
byte[] hash = HMAC_SHA256.ComputeHash(body, secretUtf8);
string hashBase64 = ToBase64String(hash);
bool isValid = hashBase64 == signature;
我在寻找Asp解决方案时偶然发现了这一点。NET应用程序检查Woocommerce web挂钩的签名。我的答案基于Johannes提供的伪代码,该代码非常有效。我实现了一个自定义控制器属性来截获请求并在其到达API控制器方法之前检查签名:
public class HmacSignatureFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var requestContent = actionContext.Request.Content;
var jsonContent = requestContent.ReadAsStringAsync().Result;
var byteContent = requestContent.ReadAsByteArrayAsync().Result;
//if the request contains this, it's the verification request from Woocommerce
//when the webhook is created so let it pass through so it can be verified
if (!jsonContent.Contains("webhook_id"))
{
var requestSignature = actionContext.Request.Headers;
var bodyHash = HashHMAC("test", byteContent); //this is the shared key between Woo and custom API. should be from config or database table.
var signature = actionContext.Request.Headers.GetValues("x-wc-webhook-signature");
if (bodyHash != signature.FirstOrDefault())
{
throw new HttpResponseException(HttpStatusCode.Forbidden);
}
}
base.OnActionExecuting(actionContext);
}
private static string HashHMAC(string key, byte[] message)
{
var keyBytes = Encoding.UTF8.GetBytes(key);
var hash = new HMACSHA256(keyBytes);
var computedHash = hash.ComputeHash(message);
return Convert.ToBase64String(computedHash);
}
}
然后要在Api控制器中使用过滤器:
[RoutePrefix("api/woo")]
public class WooController : ApiController
{
public SomeService _service;
public WooController()
{
this._service = new SomeService();
}
// POST api/values
[Route("orderCreated")]
[HttpPost]
[HmacSignatureFilter]
public string Post()
{
var requestContent = Request.Content;
var jsonContent = requestContent.ReadAsStringAsync().Result;
//this is the test request from Woocommerce. Don't do anything but
//respond so it can verify the endpoint
if (jsonContent.Contains("webhook_id"))
{
return "Webhook Test Success";
}
var wooOrder = JsonConvert.DeserializeObject<WooOrderModel>(jsonContent);
//call a service to use the order data provided by WooCommerce
_service.AddOrder(wooOrder);
return "Success";
}
}
注意:此SO帖子引用了哈希代码。