Webhooks 解析:簽名載荷與重試機制
你剛剛整合了一個會向你的端點發送 Webhook 的第三方服務。在測試環境中一切正常,但在生產環境中你卻注意到事件遺漏、重複傳遞以及偶爾的安全問題。Webhook 概念簡單但實作起來卻很棘手——尤其是在驗證真實性和處理失敗方面。
本指南說明如何使用簽名載荷保護 Webhook,並實作穩健的重試機制,以便你建立可靠的整合。
什麼是 Webhook?
Webhook 是使用者定義的 HTTP 回呼。當來源系統中發生事件(例如付款完成)時,它會向您指定的 URL 發送 HTTP POST 請求,其中包含有關事件的資料。這允許服務之間進行即時通訊,而無需輪詢。
但 Webhook 帶來了挑戰:您如何知道請求確實來自預期的發送者?如果您的端點暫時宕機怎麼辦?這就是簽名載荷和重試發揮作用的地方。
使用簽名載荷保護 Webhook
簽名載荷使用密碼學簽名來證明請求源自發送者且未被篡改。常見的方法是使用共享密鑰的 HMAC(基於雜湊的消息驗證碼)。
HMAC 簽名如何運作
發送者使用密鑰對請求主體(有時還包括時間戳等標頭)計算 HMAC。簽名在標頭中發送(例如 X-Signature)。您的伺服器重新計算 HMAC 並將其與收到的簽名進行比較。如果它們匹配,則請求是真實的。
以下是使用 Flask 的 Python 最小範例:
import hmac
import hashlib
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = b'your_shared_secret'
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-Signature')
if not signature:
abort(400, 'Missing signature')
body = request.get_data()
expected = hmac.new(SECRET, body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature):
abort(401, 'Invalid signature')
# Process the event
return '', 200
重點:
- 始終使用恆定時間比較函數(如
hmac.compare_digest)以防止計時攻擊。 - 在簽名資料中包含時間戳以防止重放攻擊;拒絕超過幾分鐘的請求。
- 保持密鑰安全——切勿在客戶端暴露。
額外的安全措施
- HTTPS: 始終使用 HTTPS 以保護傳輸中的載荷。
- IP 允許清單: 如果提供商發布了 IP 範圍,則將請求限制為這些 IP。
- 冪等性: 使用事件 ID 進行去重,因為重試可能導致重複。
實作可靠的重試
Webhook 消費者可能會失敗:您的伺服器可能宕機,或者處理可能逾時。發送者應使用指數退避重試失敗的傳遞。作為消費者,您必須優雅地處理重試。
發送者端(如果您正在建立 Webhook 系統)
- 快速返回 2xx: 在處理之前確認收到以避免逾時。使用佇列進行非同步工作。
- 失敗時重試: 如果在逾時時間內(例如 5 秒)未收到 2xx,則以遞增的延遲重試(例如 1 秒、5 秒、30 秒、5 分鐘、30 分鐘)。
- 限制重試次數: 在最大嘗試次數(例如 5 次)後,將傳遞標記為失敗並發出警報。
- 包含唯一事件 ID: 以便消費者可以去重。
消費者端(您的端點)
- 快速回應: 立即返回 2xx,並根據需要非同步處理。
- 保持冪等: 使用事件 ID 避免重複處理同一事件。
- 處理重複: 將已處理的事件 ID 儲存一段合理的時間。
- 記錄失敗: 如果處理失敗,返回 5xx 以觸發重試,但確保不會陷入迴圈。
比較:簽名載荷 vs. 基本驗證
| 方法 | 安全性 | 複雜度 | 重放保護 |
|---|---|---|---|
| HMAC 簽名 | 高(完整性 + 真實性) | 中等 | 是(帶時間戳) |
| 基本驗證 | 低(標頭中的憑證) | 低 | 否 |
| IP 允許清單 | 中(網路層級) | 低 | 否 |
在本機測試 Webhook
在開發過程中,您需要一個公開 URL 來接收 Webhook。ngrok 或 localtunnel 等工具可以公開您的本機伺服器。始終使用模擬失敗測試簽名驗證和重試行為。
檢查 Webhook 載荷時,您可能需要格式化 JSON 以提高可讀性。JSON Formatter 可以幫助您美化列印並驗證 JSON 主體。
常見問題
什麼是簽名 Webhook 載荷?
簽名載荷包含密碼學簽名(通常是 HMAC),允許接收者驗證請求的真實性和完整性。
Webhook 應該重試多少次?
沒有固定次數;常見做法是使用指數退避重試 3 到 10 次。關鍵是在可靠性和資源使用之間取得平衡,並對持續失敗發出警報。
我可以使用沒有簽名的 Webhook 嗎?
不建議。沒有簽名,您無法驗證發送者,使您的端點容易受到欺騙。在生產環境中始終使用簽名。
準備好除錯您的 Webhook 載荷了嗎?試試我們的 JSON Formatter 快速驗證和格式化 JSON 資料。