Nim Slack 机器人签名验证问题

Nim Slack bot Signature Verification Issues

我对 Nim 还很陌生,我怀疑我只是在这里做错了什么。我正在使用 Jester(用于路由等)和 Nimcrytpo(用于 hmac),但有些东西没有加起来。以下是我尝试验证签名的方式:

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

const timestampHeader = "X-Slack-Request-Timestamp"
const slackSignatureHeader = "X-Slack-Signature"
const signatureVersion = "v0"
const 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

  let baseString = signatureVersion & ':' & $timestamp & ':' & $request.body
  let mySignature = sha256.hmac(signingSecret, baseString)

  let slackSignature = MDigest[256].fromHex(request.headers[slackSignatureHeader])

  mySignature == slackSignature

我 运行 感兴趣的一些事情:

  1. 签名不匹配,我不太确定如何调试。我确实收到了来自 Slack 的有效请求,并按照此处的验证说明进行操作:https://api.slack.com/authentication/verifying-requests-from-slack#about,但它不正确。
  2. 我知道我在比较中遗漏了 v0=,但我不太确定如何通过与时间无关的比较来做到这一点(我是否应该在比较中跳过那部分等)

此时我最好的猜测是 Jester/Httpbeast 请求正文在某种程度上不够“原始”(虽然它只是普通的 json...?)或者以某种方式被处理。

任何关于如何调试的帮助或建议将不胜感激。提前致谢!

折腾了一段时间,发现自己做错了很多事!希望这对其他人有帮助:

  1. signingSecret 是从 env 中提取的,所以它不应该是一个常量——我把它移到了用 let 定义的过程本身中。
  2. headers 中的松弛签名以 v0= 为前缀,这使得 MDigest[256].fromHex() 的长度错误,因此最终成为空值(0000...) 而不是应该的。

这是一个工作版本,以防其他人需要。如果您发现任何可以改进的地方,请告诉我。

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

const timestampHeader = "X-Slack-Request-Timestamp"
const slackSignatureHeader = "X-Slack-Signature"
const signatureVersion = "v0"

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

proc verifySignature*(request: Request): bool =
  let signingSecret = os.getEnv("SLACK_SIGNING_SECRET")

  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

  let baseString = signatureVersion & ':' & $timestamp & ':' & $request.body
  let mySignature = sha256.hmac(signingSecret, baseString)

  var rawSlackSignature: string = $request.headers[slackSignatureHeader]
  rawSlackSignature.removePrefix(signatureVersion & '=')

  let slackSignature = MDigest[256].fromHex(rawSlackSignature)

  mySignature == slackSignature