2015-12-10 88 views
4

我無法成功驗證來自Trello的webhook請求。這是我所知道的。驗證Trello Webhook簽名

Trello的網絡掛接文件here狀態:

每個網絡掛接觸發器包含HTTP標頭X-Trello - 網絡掛接。標題是HMAC-SHA1哈希的base64摘要。散列的內容是完整請求主體和callbackURL的鏈接,完全像在webhook創建期間提供的一樣。用於簽署此文本的密鑰是您的應用程序的祕密。

這是可以理解的。他們繼續說

由於節點中加密實用程序的某些默認設置,我們簽名的有效內容被視爲二進制字符串,而不是utf-8。例如,如果你使用連字符(U + 2013或8211,十進制),並在Node中創建二進制緩衝區,它將顯示爲[19]的緩衝區,它是8個最不重要的這是在摘要中用於計算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 
} 

讓我知道你是否需要任何更多的信息。謝謝!

更新:已解決,請查看答案。

+0

您是否有我們可以匹配的示例請求和簽名? – JimB

+0

感謝您的關注!如果在第二天或第二天我無法正常工作,我將添加測試這些功能所需的所有信息。目前,我不願意創建一個新的Trello帳戶,只是爲了在這裏分享這個祕密。 – doykle

回答

2

你爲什麼要扔掉MSB?您正在將每個rune轉換爲byte,這是無效的(並且實際上是uint8的別名),因此該位保存您正在丟失的信息。

您可以考慮使用這樣的函數,而不是:

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

由於runeint32一個別名,中投以byte只下降了前24位,這是你想要的。

(注意:這裏假設小端。)

+0

我正在嘗試做這樣的事情,並得到溢出錯誤,這就是爲什麼'bitShift'是它的方式。這是更清潔!謝謝!但我認爲他們有相同的輸出,對吧? – doykle

+1

在一個連字符上,是的,因爲位7(零索引)是零,但不是用於設置該位的任何東西。 'bitShift'會引發這個問題,但'ascii'保留它。例如,'bitShift(0b10001110)'產生'0b00001110',其中'ascii(0b10001110)'只是給你返回不變的字節:'0b10001110'。 – mammothbane

+0

[遊樂場示例](https://play.golang.org/p/gUbmmkvRH-) – mammothbane

1

我的代碼有兩個問題。主要問題是我使用requestURL.String()作爲callbackURL

comments上述http.Request.URL

對於大多數的請求,字段比其他的路徑和RawQuery將是空的。

原來requestURL.String()只給人[Scheme]://[Host][Path][Path]部。正確的callbackURL是

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

this answer,那裏的驗證就失敗了正文中包含有8位字符的任何請求,指出了第二個問題。