doouzlrvb01417498 2015-12-10 19:10
浏览 82
已采纳

验证Trello Webhook签名

I am having trouble successfully verifying a webhook request from Trello. Here's what I know.

Trello's webhook documentation here states:

Each webhook trigger contains the HTTP header X-Trello-Webhook. The header is a base64 digest of an HMAC-SHA1 hash. The hashed content is the concatenation of the full request body and the callbackURL exactly as it was provided during webhook creation. The key used to sign this text is your application’s secret.

Which is understandable. They go on to say

Because of certain defaults in the crypto utilities in node, the payloads that we sign are treated as binary strings, not utf-8. For example, if you take the en-dash character (U+2013 or 8211 in decimal), and create a binary buffer out of it in Node, it will show up as a buffer of [19], which are the 8 least significant bits of 8211. That is the value that is being used in the digest to compute the SHA-1.

This is less clear to me. My understanding is that each character of the payload (body + callbackURL) has been put into an 8-bit integer, with the overflow ignored. (Because 8211 == 0b10000000010011, and 0b00010011 == 19) This is where I think my problem is.

The function I am using to accommodate Trello's node payload issue is:

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
}

It is also very possible that I am doing something wrong with the basic verification step. It looks okay to me, though I am somewhat new to this.

// 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
}

Let me know if you need any more information. Thank you!

Update: This is solved, check out the answers.

  • 写回答

2条回答 默认 最新

  • dongzhi4690 2015-12-11 03:49
    关注

    Why are you throwing away the MSB? You're converting each rune to byte, which is signless (and actually an alias for uint8), so that bit holds information that you're losing.

    You might consider using a function like this instead:

    func ascii(s string) []byte {
        var ret []byte
        for _, r := range s {
            ret = append(ret, byte(r))
        }
        return ret
    }
    

    Since rune is an alias for int32, the cast to byte just drops the top 24 bits, which is what you want.

    (Caveat: this assumes little-endianness.)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥30 YOLO检测微调结果p为1
  • ¥20 求快手直播间榜单匿名采集ID用户名简单能学会的
  • ¥15 DS18B20内部ADC模数转换器
  • ¥15 做个有关计算的小程序
  • ¥15 MPI读取tif文件无法正常给各进程分配路径
  • ¥15 如何用MATLAB实现以下三个公式(有相互嵌套)
  • ¥30 关于#算法#的问题:运用EViews第九版本进行一系列计量经济学的时间数列数据回归分析预测问题 求各位帮我解答一下
  • ¥15 setInterval 页面闪烁,怎么解决
  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题