使用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
相关产品推荐
相关产品推荐

