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

.NET中Slack API请求签名验证始终不匹配问题排查

解决Slack API请求签名验证不匹配的问题

核心问题分析

你的代码存在几个关键问题,直接导致签名无法匹配:

  • 时间戳未正确获取:代码中timestampUnix变量未定义,未从X-Slack-Request-Timestamp请求头提取有效值。
  • 请求体处理错误:手动拼接request.Form生成请求体的方式会丢失原始请求的编码细节(比如特殊字符的URL编码、参数顺序),Slack签名是基于原始请求体的字节流,而非解析后重新拼接的内容。
  • 请求头取值未处理多值情况:headers["X-Slack-Request-Timestamp"]返回StringValues类型,直接拼接会导致格式错误。

修正后的代码实现

private bool VerifySlackRequest(HttpRequest request, IHeaderDictionary headers, StringValues slackSignatureHeader)
{
    string slackSigningSecret = ConfigurationHelper.SlackSigningSecret;

    // 1. 从请求头提取并验证时间戳
    if (!long.TryParse(headers["X-Slack-Request-Timestamp"].FirstOrDefault(), out long timestampUnix))
    {
        return false;
    }

    DateTime timestamp = DateTimeOffset.FromUnixTimeSeconds(timestampUnix).UtcDateTime;
    DateTime currentTimestamp = DateTime.UtcNow;

    if (Math.Abs((currentTimestamp - timestamp).TotalSeconds) > 60 * 5)
    {
        // 请求时间戳超出5分钟,判定为重放攻击
        return false;
    }

    // 2. 读取原始请求体(关键:不能使用解析后的Form数据)
    request.Body.Position = 0; // 重置流位置,确保读取完整内容
    using var reader = new StreamReader(request.Body);
    string requestBody = reader.ReadToEnd();
    request.Body.Position = 0; // 重置位置,避免后续处理无法读取请求体

    // 3. 生成签名并安全对比
    var encoding = new UTF8Encoding();
    string baseString = $"v0:{timestampUnix}:{requestBody}";
    using var hmac = new HMACSHA256(encoding.GetBytes(slackSigningSecret));
    byte[] hashBytes = hmac.ComputeHash(encoding.GetBytes(baseString));
    string computedSignature = $"v0={BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant()}";

    // 使用常量时间比较,防止时序攻击
    return CryptographicOperations.FixedTimeEquals(encoding.GetBytes(computedSignature), encoding.GetBytes(slackSignatureHeader));
}

关键修正说明

  • 原始请求体读取:直接读取request.Body的原始内容,避免解析后拼接带来的编码、参数顺序差异,这是签名匹配的核心。
  • 时间戳有效性校验:添加long.TryParse确保时间戳格式合法,避免空值或非数字导致的错误。
  • 安全的签名对比:用CryptographicOperations.FixedTimeEquals替代普通Equals,防止攻击者通过时序差异破解签名。
  • 流位置重置:读取请求体后重置流位置,保证后续中间件或业务逻辑能正常读取请求内容。

额外检查项

  • 确认SlackSigningSecret是从Slack后台复制的完整值,无多余空格或换行。
  • 若请求经过反向代理(如NGINX),需确保代理未修改原始请求体(比如自动URL解码),需配置代理保留原始请求内容。

内容的提问来源于stack exchange,提问作者Hager Khaled

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 05:12:28