签名验证标准
不同平台的签名串拼接顺序、摘要算法、Base64 和 URL 编码规则并不通用。实现时必须逐字段遵循对应平台官方文档,不能把飞书、钉钉、Slack 或企业微信的算法互相替换。
入站回调验证
Section titled “入站回调验证”推荐处理顺序:
- 限制请求体大小和 HTTP 方法。
- 保存原始请求体字节,不先解析再序列化。
- 读取平台规定的时间戳、随机数、签名或密文头。
- 拒绝超过允许时间窗口的请求。
- 按平台规定生成期望签名,并使用常量时间比较。
- 以事件 ID 或“时间戳 + 随机数 + 摘要”建立短期重放记录。
- 验证成功后再解密、解析和执行业务。
出站 Webhook 签名
Section titled “出站 Webhook 签名”调用群机器人时,签名通常由当前时间戳和机器人 Secret 生成,并随请求参数或请求体发送。服务器时间偏差、毫秒和秒混用、换行符不一致、Base64 后漏做 URL 编码,是最常见的失败原因。
先使用固定时间戳和固定 Secret 建立官方示例测试向量,再接入系统时钟。签名失败不能无限重试,因为同一错误参数不会自行恢复。
时间与重放窗口
Section titled “时间与重放窗口”- 服务端启用可靠的时间同步并监控时钟偏差。
- 接受窗口以平台规定为准,不自行扩大到数小时。
- 重放记录的过期时间至少覆盖接受窗口。
- 事件去重和签名防重放是两层控制:签名证明请求来源,事件 ID 防止已通过验证的事件被重复执行业务。
平台支持双密钥时采用重叠窗口:新密钥先发布到验证端,再切换平台配置,最后撤销旧密钥。只支持单密钥时应准备短暂维护窗口,并在切换前暂停非必要重试。日志只记录密钥版本,不记录密钥值或完整签名材料。
- 正确签名请求通过。
- 请求体改变一个字节后失败。
- 时间戳过期或来自未来时失败。
- 同一事件重复到达时只执行业务一次。
- 密钥错误时返回明确的客户端错误,不进入重试队列。
- 日志和错误响应不包含 Secret、Token、完整 Webhook 或解密后的敏感内容。