猿问

验证 Trello Webhook 签名

我在成功验证来自 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

}

如果您需要更多信息,请告诉我。谢谢!


更新:这已解决,请查看答案。


慕沐林林
浏览 163回答 2
2回答

九州编程

你为什么要扔掉 MSB?您将每个都转换rune为byte,这是无符号的(实际上是 的别名uint8),因此该位包含您正在丢失的信息。您可能会考虑使用这样的函数:func ascii(s string) []byte {&nbsp; &nbsp; var ret []byte&nbsp; &nbsp; for _, r := range s {&nbsp; &nbsp; &nbsp; &nbsp; ret = append(ret, byte(r))&nbsp; &nbsp; }&nbsp; &nbsp; return ret}由于rune是 的别名int32,因此强制转换byte仅删除前 24 位,这正是您想要的。(警告:这假设小端。)

翻阅古今

我的代码有两个问题。主要问题是我requestURL.String()对callbackURL.在上面的评论中http.Request.URL:对于大多数请求,除 Path 和 RawQuery 之外的字段将为空。原来,那requestURL.String()只是给的[Path]部分[Scheme]://[Host][Path]。正确的 callbackURL 是callbackURL&nbsp;:=&nbsp;"https://"&nbsp;+&nbsp;request.Host&nbsp;+&nbsp;request.URL.String()这个答案中指出了第二个问题,对于任何正文包含第 8 位字符的请求,验证都会失败。
随时随地看视频慕课网APP

相关分类

Go
我要回答