Webhook解説:署名付きペイロードとリトライ
Webhookが強力でありながら壊れやすい理由
Webhookはリアルタイム連携を支えます:決済通知、CI/CDトリガー、チャットメッセージなど。しかし、2つの大きな課題があります:セキュリティ(リクエストが期待された送信元からのものだとどうやって確認するか?)と信頼性(受信側がダウンしていたらどうするか?)です。この記事では、署名付きペイロードとリトライ戦略で両方に対処する方法を紹介します。
Webhookとは何か?
Webhookとは、イベントが発生したときにプロバイダーからコンシューマーへ送信されるHTTP POSTリクエストです。ポーリングとは異なり、Webhookはほぼリアルタイムでデータをプッシュするため、レイテンシとサーバー負荷を軽減します。プロバイダーはリクエストが真正であることを保証し、コンシューマーはそれを確実に処理する必要があります。
署名付きペイロードでWebhookを保護する
署名付きペイロードは、秘密鍵を使ってリクエストボディの暗号署名(通常はHMAC-SHA256)を生成します。受信側は署名を再計算し、ヘッダー内の署名と比較します。一致すれば、ペイロードは真正で改ざんされていないことになります。
署名の生成と検証方法
典型的なフローは次のとおりです:
- プロバイダーとコンシューマーが秘密鍵を共有する(例:ダッシュボード経由)。
- プロバイダーが
HMAC-SHA256(secret, payload)を計算し、X-Signatureのようなヘッダーで送信する。 - コンシューマーが生のボディを読み取り、同じHMACを計算し、定数時間関数で比較する。
Node.jsの例:
const crypto = require('crypto');
function verifySignature(secret, payload, signature) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(payload);
const digest = hmac.digest('hex');
return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(signature));
}
タイミング攻撃を防ぐため、常に定数時間比較を使用してください。検証前にボディをパースしないこと—生のボディミドルウェアを使用してください。
信頼性の高い配信のためのリトライ実装
署名があっても、ネットワーク障害や一時的な停止によりWebhook配信が失敗することがあります。堅牢なリトライ機構が最終的な配信を保証します。
リトライ戦略
- 指数バックオフ:各リトライ間の待機時間を長くする(例:1秒、2秒、4秒、8秒)。
- 最大試行回数:無限ループを避けるためリトライを制限する(例:5回)。
- デッドレターキュー:最大試行回数後に、手動検査用にイベントを保存する。
- 冪等性:一意のイベントIDを含めて、コンシューマーが重複を無視できるようにする。
Pythonでのリトライロジックの例:
import time
import requests
def send_webhook(url, payload, max_retries=5):
for attempt in range(max_retries):
try:
response = requests.post(url, json=payload, timeout=5)
if response.status_code == 200:
return True
except requests.RequestException:
pass
time.sleep(2 ** attempt) # exponential backoff
return False
Webhookコンシューマーのベストプラクティス
- 素早く2xxで応答する;必要なら非同期で処理する。
- 処理前に署名を検証する。
- 冪等性キーを使って重複配信を処理する。
- デバッグ用にすべての受信Webhookをログに記録する。
- 失敗を監視し、繰り返しエラーが発生したらアラートを出す。
比較:ポーリング vs Webhook
| 項目 | ポーリング | Webhook |
|---|---|---|
| レイテンシ | 高い(間隔ベース) | 低い(リアルタイム) |
| サーバー負荷 | 常時リクエスト | イベント時のみ |
| 複雑さ | シンプル | リトライ/セキュリティが必要 |
| ユースケース | 小規模、更新頻度が低い | リアルタイム連携 |
FAQ
署名付きWebhookペイロードとは何ですか?
署名付きペイロードには暗号署名(例:HMAC)が含まれており、受信側がリクエストが信頼できる送信元から来たもので改ざんされていないことを検証できます。
失敗したWebhookを何回リトライすべきですか?
普遍的な回数はありませんが、指数バックオフで3〜5回が一般的です。その後は手動レビュー用にイベントをログに記録します。
Webhook署名にHMACの代わりにJWTを使えますか?
はい、一部のプロバイダーはJWTを使用しています。原則は同じです:ペイロードを信頼する前にトークンの署名とクレームを検証します。
Webhookペイロードやログを確認する必要がありますか?JSON Formatterを使って、JSONペイロードをすばやく整形して検証できます。