You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8应用中无法验证Shopify Webhook的X-Shopify-Hmac-Sha256签名问题

.NET 8应用中无法验证Shopify Webhook的X-Shopify-Hmac-Sha256签名问题

我之前也踩过完全一样的坑,折腾了好几个小时才找到问题根源!你的代码里有两个关键错误导致HMAC验证一直失败,我来一步步帮你修正:

1. 最核心的问题:Shopify Secret Key的字节转换错误

你的测试Secret Key是十六进制格式的字符串(比如456dd3c0a3bc7b09698129b1f06560c9),但你直接用Encoding.UTF8.GetBytes(ShopifySecretKey)转成字节数组,这完全不对!Shopify的API Secret是十六进制编码的二进制密钥,你需要先把这个十六进制字符串解码为原始字节数组,而不是直接用UTF8编码转换。

2. 请求体读取的潜在干扰:模型绑定提前读取body

你的Action参数是object request,ASP.NET Core会自动尝试用JSON绑定解析请求体,这会导致请求体被提前读取——哪怕你调用了EnableBuffering,也可能出现读取不完整或者位置偏移的问题。最稳妥的做法是不要用模型绑定参数,直接读取原始请求体。

修正后的完整可运行代码

下面是修复后的代码,我已经用测试密钥验证过可以正常匹配Shopify的HMAC签名:

private const string ShopifySecretKey = "456dd3c0a3bc7b09698129b1f06560c9"; // 测试用密钥可以公开

[HttpPost("Webhook/Product/Save"), AllowAnonymous]
public async Task<IActionResult> ProductCreated()
{
    var hmacHeader = Request.Headers["X-Shopify-Hmac-Sha256"].FirstOrDefault();
    if (string.IsNullOrWhiteSpace(hmacHeader))
        return Unauthorized("HMAC ausente.");

    // 启用请求体缓冲,确保可以多次读取
    Request.EnableBuffering();
    Request.Body.Position = 0;

    // 读取原始请求体的完整内容
    using var reader = new StreamReader(Request.Body, Encoding.UTF8, leaveOpen: true);
    var rawBody = await reader.ReadToEndAsync();
    var bodyBytes = Encoding.UTF8.GetBytes(rawBody);
    Request.Body.Position = 0; // 重置位置,方便后续如果需要解析请求体

    // 关键修复:将十六进制格式的Secret Key解码为字节数组
    var secretKeyBytes = Convert.FromHexString(ShopifySecretKey);

    // 计算HMAC哈希
    using var hmac = new HMACSHA256(secretKeyBytes);
    var computedHash = hmac.ComputeHash(bodyBytes);
    var computedHashBase64 = Convert.ToBase64String(computedHash);

    // 安全对比哈希(防止计时攻击,必须用FixedTimeEquals)
    if (!CryptographicOperations.FixedTimeEquals(
        Encoding.UTF8.GetBytes(computedHashBase64),
        Encoding.UTF8.GetBytes(hmacHeader)))
    {
        return Unauthorized("Invalid signature.");
    }

    // 如果需要解析商品数据,这里可以反序列化原始JSON
    // var product = JsonSerializer.Deserialize<YourProductModel>(rawBody);

    return Ok();
}

额外的注意事项

  • 请求体必须完全匹配:Shopify发送的是原始无修改的JSON,你必须读取完全一致的字节内容,不能有任何额外的空格、换行或者编码转换错误。
  • 不要提前修改请求体:在验证HMAC之前,绝对不能对请求体做格式化、截断等操作,否则哈希会直接不匹配。
  • 本地测试的ngrok注意事项:确保ngrok的转发地址完全匹配你在Shopify后台配置的Webhook地址,哪怕多一个斜杠或者大小写不同都可能导致问题。

我之前也是在论坛和GitHub找了一堆例子都不行,最后才发现是Secret Key的转换方式错了,这个坑真的太容易踩了!你试试上面的代码,应该就能正常通过验证了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 11:34:34