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

在C#中验证Zendesk Webhook签名有效性遇阻求助

Zendesk Webhook签名验证C#代码修复方案

尝试用C#验证Zendesk Webhook签名有效性但代码无法运行,原代码如下:

string json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
string signature = Request.Headers["x-zendesk-webhook-signature"];
string timestamp = Request.Headers["x-zendesk-webhook-signature-timestamp"];
            
// Signing secret from webhook itself 
string SIGNING_SECRET = "Secret key";
            
_logger.LogDebug("Zendesk signature: " + signature);
_logger.LogDebug("Zendesk timestamp: " + timestamp);
_logger.LogDebug("Zendesk body: " + json);
var b1 = timestamp + json;
string newSignature = "";

using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(SIGNING_SECRET)))
{
    var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(b1));
    newSignature = Convert.ToBase64String(hash);
}

return signature.Equals(newSignature, StringComparison.OrdinalIgnoreCase);

参考的Zendesk官方验证逻辑(Node.js版本文档):将请求头中的时间戳与原始请求体拼接,使用Webhook的签名密钥通过HMAC-SHA256算法生成哈希值,再转换为Base64编码,最后与请求头中的签名值比对,同时需验证时间戳防止重放攻击。

问题排查与修复点:

  • 请求体读取与编码:原代码未指定StreamReader编码,可能导致请求体字符串编码异常;且读取后未重置流位置,会影响后续对请求体的操作。
  • 时间戳验证缺失:未检查时间戳的有效性,存在重放攻击风险,也不符合官方安全要求。
  • 签名比对逻辑:Base64编码大小写敏感,原代码用OrdinalIgnoreCase比对可能导致不匹配。
  • 请求体完整性:确保读取的是原始未修改的请求体,不要对JSON做格式化、缩进等操作,否则会导致哈希值不匹配。

修复后的代码:

using System.Security.Cryptography;
using System.Text;

// 以UTF-8编码读取原始请求体,确保与Zendesk发送的内容一致
var rawBody = await new StreamReader(HttpContext.Request.Body, Encoding.UTF8).ReadToEndAsync();
// 重置请求体流位置,避免后续处理请求体时出错
HttpContext.Request.Body.Position = 0;

string receivedSignature = Request.Headers["x-zendesk-webhook-signature"];
string receivedTimestamp = Request.Headers["x-zendesk-webhook-signature-timestamp"];

// 从Zendesk Webhook设置中获取的签名密钥
string signingSecret = "你的签名密钥";

// 1. 验证时间戳有效性,防止重放攻击
if (!long.TryParse(receivedTimestamp, out long timestamp))
{
    return false;
}
var currentUnixTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
// 允许5分钟的时间误差,可根据需求调整
if (Math.Abs(currentUnixTime - timestamp) > 300)
{
    return false;
}

// 2. 拼接时间戳与原始请求体
var dataToSign = receivedTimestamp + rawBody;

// 3. 生成HMAC-SHA256哈希并转为Base64
string computedSignature;
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(signingSecret)))
{
    var hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
    computedSignature = Convert.ToBase64String(hashBytes);
}

// 4. 严格比对签名(Base64大小写敏感)
return computedSignature.Equals(receivedSignature, StringComparison.Ordinal);

内容的提问来源于stack exchange,提问作者Hardik Masalawala

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 20:10:31