如何创建匹配的HMAC值以validation.NET中的Shopify WebHook?

我已经设置了一个端点来接收Shopify的webhook请求。

Shopify的请求包括从共享密钥和请求正文创建的HMAC标头。

我需要在服务器上计算HMAC并将其与请求标头中的值相匹配,以确保请求是可信的。

我似乎无法在.NET中创建适当的机制来创建匹配的HMAC值。

我的算法在这一点如下:

public static string CreateHash(string data) { string sharedSecretKey = "MY_KEY"; byte[] keyBytes = Encoding.UTF8.GetBytes(sharedSecretKey); byte[] dataBytes = Encoding.UTF8.GetBytes(data); //use the SHA256Managed Class to compute the hash System.Security.Cryptography.HMACSHA256 hmac = new HMACSHA256(keyBytes); byte[] hmacBytes = hmac.ComputeHash(dataBytes); //retun as base64 string. Compared with the signature passed in the header of the post request from Shopify. If they match, the call is verified. return System.Convert.ToBase64String(hmacBytes); } 

可以在此处找到用于validation其webhook的Shopify文档,但仅包含PHP和Ruby示例。

任何人都可以看到我可能做错了什么? 我应该只是将整个JSON请求体作为字符串传递给此方法吗?

正如您在问题中提到的那样,您应该在方法中对整个json请求体进行哈希处理。

我的.NET不太好,但这是ruby示例的一部分,它向您展示了如何做:

 post '/' do . . . data = request.body.read verified = verify_webhook(data, env["HTTP_X_SHOPIFY_HMAC_SHA256"]) . . . end 

您可以看到我们只是抓住请求的主体(作为字符串)并将其逐字地放入validation方法中。 尝试一下,希望你会有更多的运气。

  private static bool Validate(string sharedSecretKey) { var data = GetStreamAsText(HttpContext.Current.Request.InputStream, HttpContext.Current.Request.ContentEncoding); var keyBytes = Encoding.UTF8.GetBytes(sharedSecretKey); var dataBytes = Encoding.UTF8.GetBytes(data); //use the SHA256Managed Class to compute the hash var hmac = new HMACSHA256(keyBytes); var hmacBytes = hmac.ComputeHash(dataBytes); //retun as base64 string. Compared with the signature passed in the header of the post request from Shopify. If they match, the call is verified. var hmacHeader = HttpContext.Current.Request.Headers["x-shopify-hmac-sha256"]; var createSignature = Convert.ToBase64String(hmacBytes); return hmacHeader == createSignature; } private static string GetStreamAsText(Stream stream, Encoding encoding) { var bytesToGet = stream.Length; var input = new byte[bytesToGet]; stream.Read(input, 0, (int)bytesToGet); stream.Seek(0, SeekOrigin.Begin); // reset stream so that normal ASP.NET processing can read data var text = encoding.GetString(input); return text; }