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

使用C#验证Slack Events API请求时签名不匹配问题咨询

问题原因与修复方案

一、原始请求体一致性校验方法

你看到的"是IDE调试窗口的自动转义显示,并非请求体的真实内容,要确认请求体是否完全匹配可按以下步骤操作:

  • 不要使用模型绑定后反序列化再序列化得到的JSON作为签名原料,这类操作会改变原始JSON的空格、属性顺序、转义规则,和Slack端的原始payload完全不一致。你当前直接从InputStream读取原始流的逻辑是对的。
  • 把读取到的requestBody直接写入本地纯文本文件,和Slack请求的原始抓包内容做逐字符对比,不要依赖IDE的变量预览窗口。
  • 确认ASP.NET管道没有提前读取修改请求流:如果你的接口方法用了[FromBody]参数,框架会自动提前解析请求体,可能导致你读取InputStream时拿到的内容异常,要么移除[FromBody]参数,要么提前配置请求体允许重复读取。

二、HMACSHA256用法错误点

你当前代码的核心错误是签名基础串的编码用了ASCII而非UTF-8:如果Slack的请求payload里包含非ASCII字符(比如中文、特殊符号),ASCII编码会丢失字节导致哈希计算错误。

三、修改后的可运行代码

{
...
    string signingKey = ConfigurationManager.AppSettings["Slack:SigningSecret"].ToString();            
    string timestamp = GetHeaderValue(actionContext, "X-Slack-Request-Timestamp");            
    string SlackSignature = GetHeaderValue(actionContext, "X-Slack-Signature");

    // 可选:先校验时间戳和当前时间差不超过5分钟,避免重放攻击
    if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - long.Parse(timestamp)) > 300)
    {
        throw new HttpResponseException(HttpStatusCode.Forbidden);
    }

    var app = HttpContext.Current;
    string requestBody = string.Empty;
    using (var stream = new MemoryStream())
    {
        app.Request.InputStream.Seek(0, SeekOrigin.Begin);
        app.Request.InputStream.CopyTo(stream);
        requestBody = Encoding.UTF8.GetString(stream.ToArray());                
        app.Request.InputStream.Seek(0, SeekOrigin.Begin);                
    }  

    string sig_basestring = "v0:" + timestamp + ":" + requestBody;
    var hmac256 = HMACSHA256.Create();
    hmac256.Key = Encoding.ASCII.GetBytes(signingKey);
    // 修复:用UTF-8编码计算哈希
    var sig_hash = hmac256.ComputeHash(Encoding.UTF8.GetBytes(sig_basestring));

    var computedSignature = "v0=" + ToHex(sig_hash, false);
    // 可选:用时序安全的比较方法避免时序攻击
    bool isValidRequest = SlackSignature.Equals(computedSignature);

    if (!isValidRequest)
    {
        throw new HttpResponseException(HttpStatusCode.Forbidden);
    }
...
}

private string ToHex(byte[] bytes, bool upperCase) 
{
    var result = new StringBuilder(bytes.Length * 2);
    for (int i = 0; i < bytes.Length; i++)
        result.Append(bytes[i].ToString(upperCase ? "X2" : "x2"));
    return result.ToString();
}

内容的提问来源于stack exchange,提问作者Rick LaBarbera

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 13:54:03