在串接對方 webhooks 時通常會看到文件上提到 signature「簽章」,可以感覺的到它應該跟驗證或什麼安全有關,但詳細到底怎麼運作呢?
其實簽章的概念很簡單,用信件來比喻的話,就是讓收信方能驗證這封信是真的出自他認識的人,而非偽造的。所以當我們收到信時,就必須先檢查這封信上的簽名是否依據我們私下約定好的方式簽寫,比方說簽完名要多畫一顆愛心。而當有心人士想偽造假信寄給我們時,他也許知道要偽造簽什麼名,但他不知道簽完還要畫愛心,這樣收信的我們就能識破沒有愛心的信是假的了。
回到 webhook signature,其實也是一樣的,收送雙方需要先約定好兩樣不讓外人知道的東西:簽什麼名(content)、和要多畫什麼圖(secret)。以以下 HTTP request 為例,我們可以約定好 message 內容接 timestamp 在後頭是 content,而 secret 是 draw_a_heart,以HMAC-SHA256加密,最後把做好的簽章也放在 body 裡。
POST /my/webhook/endpoint HTTP/1.1
Host: my.web
Content-Type: application/json
{
"signature": "b18dcf385031a45c0e7f805a50f6ac3d8799d702072c4b79cd9a1d026cf8ecd4"
"timestamp": 1631634099,
"message" : "Gawr Gura is the best <3"
}
所以我們收到信後可以拿 message 和 secret 去產生簽證,再跟我們收的簽章做比對,就知道訊息是否來自約定的對方了。
以 PHP 為例
/**
*
* @return boolean 驗證成功回傳 true,失敗回傳 false
*
*/
function verify($request)
{
return $request->signature === hash_hmac(
'sha256',
$request->message . $request->timestamp,
$secret
);
}
可以用線上工具驗證看看 Online hash tool