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

无法验证来自Bot的Slack Events API请求问题排查

Slack Bot消息触发Events API时签名验证失败(Signature Mismatch)排查与修复

问题核心

开发集成ChatGPT的Slack反馈机器人时,用户发送消息触发的Events API请求能通过签名验证,但Bot自身发送消息触发的event_callback请求出现签名不匹配错误。当前因无法获取原始请求体(rawBody始终为undefined),只能用JSON.stringify(request.body)替代,导致签名计算不一致。

关键原因分析

Slack的请求签名是基于原始HTTP请求体的字节内容生成的,而JSON.stringify(request.body)会破坏原始请求体的一致性:

  1. 键顺序差异:JavaScript对象解析后再序列化为JSON时,键的顺序可能与Slack发送的原始JSON不一致
  2. 格式差异:序列化过程可能自动添加/移除空格、转换值类型(如空字符串转undefined)
  3. 字段修改:中间件可能对解析后的request.body进行了增删字段操作

这些差异会导致签名计算用的basestring与Slack生成的不一致,最终触发签名不匹配错误。

修复方案

方案1:优先获取原始请求体(推荐)

不同框架获取rawBody的方式不同,以下是常见框架的实现示例:

  • Express:通过监听请求流手动收集原始内容,再解析JSON
import express from 'express';
const app = express();

// 先收集rawBody,再解析JSON
app.use((req, res, next) => {
  let rawBody = '';
  req.on('data', chunk => rawBody += chunk.toString());
  req.on('end', () => {
    (req as any).rawBody = rawBody;
    next();
  });
});
app.use(express.json());

获取到rawBody后,直接用它作为验证函数的body参数,无需序列化。

方案2:强制JSON序列化匹配原始格式

若确实无法获取rawBody,需严格保证序列化后的字符串与Slack原始请求体一致:

  1. 固定键顺序:按照Slack发送的event_callback请求体的键顺序,手动指定序列化顺序
  2. 避免类型转换:确保解析后的request.body字段类型与原始请求体完全一致(如空字符串不能变为undefined)

调整调用代码如下:

// 定义Slack event_callback请求体的固定键顺序
const slackEventKeys = [
  'token', 'team_id', 'context_team_id', 'context_enterprise_id',
  'api_app_id', 'event', 'type', 'event_id', 'event_time',
  'authorizations', 'is_ext_shared_channel', 'event_context'
];

// 优先用rawBody,否则用固定键顺序序列化
const bodyToVerify = rawBody as string || JSON.stringify(request.body, slackEventKeys);

const verificationOptions: SlackRequestVerificationOptions = {
  signingSecret,
  body: bodyToVerify,
  headers: {
    'x-slack-signature': headers['x-slack-signature'] as string,
    'x-slack-request-timestamp': headers['x-slack-request-timestamp'] as string,
  },
  millisecondsNow: Date.now(),
};

verifySlackRequest(verificationOptions);

验证排查步骤

  1. 对比原始请求体(可通过抓包或日志获取)与JSON.stringify(request.body)的输出,检查是否存在键顺序、格式或值的差异
  2. 打印签名计算用的basestring,确认与Slack文档中描述的格式一致(v0:timestamp:raw_body)
  3. 检查request.body是否被中间件修改过(如添加额外字段、转换值类型)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 14:03:11