为了账号安全,请及时绑定邮箱和手机立即绑定

验证 Trello Webhook 签名

验证 Trello Webhook 签名

Go
慕沐林林 2021-11-29 15:47:46
我在成功验证来自 Trello 的 webhook 请求时遇到问题。这是我所知道的。Trello 的 webhook 文档在这里指出:每个 webhook 触发器都包含 HTTP 标头 X-Trello-Webhook。标头是 HMAC-SHA1 哈希的 base64 摘要。散列内容是完整的请求正文和 callbackURL 的串联,与在 webhook 创建期间提供的完全一样。用于签署此文本的密钥是您的应用程序的秘密。这是可以理解的。他们接着说由于 node 中加密实用程序的某些默认值,我们签名的有效负载被视为二进制字符串,而不是 utf-8。例如,如果您使用破折号字符(十进制的 U+2013 或 8211),并在 Node 中用它创建一个二进制缓冲区,它将显示为 [19] 的缓冲区,这是 8 个最低有效值8211 位。这是摘要中用于计算 SHA-1 的值。这对我来说不太清楚。我的理解是负载(body + callbackURL)的每个字符都被放入了一个 8 位整数,忽略了溢出。(因为 8211 == 0b10000000010011 和 0b00010011 == 19)这就是我认为我的问题所在。我用来解决 Trello 节点负载问题的函数是:func bitShift(s string) []byte {    var byteString []byte    // For each rune in the string    for _, c := range s {        // Create a byte slice        b := []byte(string(c))        // Take the sign off the least significant byte        tmp := b[len(b)-1] << 1        tmp = tmp >> 1        // Append it to the byte string        byteString = append(byteString, tmp)    }    return byteString}我也很可能在基本验证步骤中做错了。对我来说看起来不错,虽然我对此有点陌生。// VerifyNotificationHeader ...func VerifyNotificationHeader(signedHeader, trelloAPISecret string, requestURL *url.URL, body []byte) bool {    // Put callbackURL and body into byte slice    urlBytes := bitShift(requestURL.String())    bitBody := bitShift(string(body))    // Sign, hash, and encode the payload    secret := []byte(trelloAPISecret)    keyHMAC := hmac.New(sha1.New, secret)    keyHMAC.Write(append(bitBody, urlBytes...))    signedHMAC := keyHMAC.Sum(nil)    base64signedHMAC := base64.StdEncoding.EncodeToString(signedHMAC)    if comp := strings.EqualFold(base64signedHMAC, signedHeader); !comp {        return false    }    return true}如果您需要更多信息,请告诉我。谢谢!更新:这已解决,请查看答案。
查看完整描述

2 回答

?
九州编程

TA贡献1785条经验 获得超4个赞

你为什么要扔掉 MSB?您将每个都转换rune为byte,这是无符号的(实际上是 的别名uint8),因此该位包含您正在丢失的信息。


您可能会考虑使用这样的函数:


func ascii(s string) []byte {

    var ret []byte

    for _, r := range s {

        ret = append(ret, byte(r))

    }

    return ret

}

由于rune是 的别名int32,因此强制转换byte仅删除前 24 位,这正是您想要的。


(警告:这假设小端。)


查看完整回答
反对 回复 2021-11-29
?
翻阅古今

TA贡献1780条经验 获得超5个赞

我的代码有两个问题。主要问题是我requestURL.String()callbackURL.

在上面的评论中http.Request.URL

对于大多数请求,除 Path 和 RawQuery 之外的字段将为空。

原来,那requestURL.String()只是给的[Path]部分[Scheme]://[Host][Path]。正确的 callbackURL 是

callbackURL := "https://" + request.Host + request.URL.String()

这个答案中指出了第二个问题,对于任何正文包含第 8 位字符的请求,验证都会失败。


查看完整回答
反对 回复 2021-11-29
  • 2 回答
  • 0 关注
  • 162 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信