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

Nim开发Slack bot时Jester+Nimcrypto签名验证不匹配问题求助

核心问题修复方案

1. 签名前缀处理

Slack返回的X-Slack-Signature头固定为v0=xxxx格式,你当前直接将整个头值传入fromHex的逻辑完全错误,v0=不属于十六进制字符,会导致解析出的摘要完全失真。
抗时序对比时确实需要跳过前缀,直接取头值去掉前3位v0=的部分做十六进制解析即可,nimcrypto中MDigest的==运算符本身实现了抗时序对比逻辑,可以直接使用。

2. Jester请求body预处理问题

你的推测正确,Jester默认会对application/x-www-form-urlencoded类型的请求做自动表单解析,解析完成后request.body会被置空,你拿到的不是原始请求载荷。
解决方案有两种:

  • 全局关闭Jester的自动表单解析,在路由定义前添加配置settings.formParse = false
  • 直接读取原生Httpbeast请求的body:Jester的Request对象内置req字段对应原生Httpbeast请求,通过$request.req.body即可拿到未被修改的原始载荷

3. 隐藏问题:签名密钥读取逻辑错误

你当前将signingSecret定义为const是完全错误的,const为编译期求值,编译阶段就会读取当时的环境变量值写死到二进制中,运行时不会读取系统实际的环境变量,需要改为let做运行时读取。


修正后核心代码

import jester
import dotenv
import os, strutils, times
import nimcrypto

const timestampHeader = "X-Slack-Request-Timestamp"
const slackSignatureHeader = "X-Slack-Signature"
const signatureVersion = "v0"
# 改为运行时读取环境变量
let signingSecret = os.getEnv("SLACK_SIGNING_SECRET")

proc isTimestampRecent(timestamp: int): bool =
  abs(getTime().toUnix - timestamp) <= (60 * 5)

proc verifySignature*(request: Request): bool =
  if (not request.headers.hasKey timestampHeader) or
  (not request.headers.hasKey slackSignatureHeader):
    return false

  let timestamp = request.headers[timestampHeader].parseInt
  if not timestamp.isTimestampRecent():
    return false

  # 读取原始请求body
  let rawBody = $request.req.body
  let baseString = signatureVersion & ':' & $timestamp & ':' & rawBody
  let mySignature = sha256.hmac(signingSecret, baseString)

  # 去掉签名前缀后再解析
  let slackSigRaw = request.headers[slackSignatureHeader].stripPrefix(signatureVersion & "=")
  let slackSignature = MDigest[256].fromHex(slackSigRaw)

  return mySignature == slackSignature

# 关闭自动表单解析,避免body被清空
settings.formParse = false

routes:
  post "/slack/events":
    if verifySignature(request):
      resp "ok"
    else:
      resp Http403, "invalid signature"

调试思路

如果修改后还是校验失败,可按以下步骤排查:

  • 打印请求timestamp、原始body、生成的baseString、本地计算的签名、Slack返回的签名值,逐段对比确认哪个环节数据异常
  • 用curl构造模拟请求,手动计算签名后发送到服务端,排除网络传输或Slack端配置错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 08:54:02