Webhook解説:署名付きペイロードとリトライ戦略
Webhookが失敗する理由とその修正方法
アプリで注文ステータスを更新するために、決済プロバイダのWebhookを統合したばかりでしょう。テストではすべてがうまくいきますが、本番環境では一部のイベントが届かなかったり、さらに悪いことに重複して受信したりします。適切な保護措置がないと、Webhookはサイレント障害やセキュリティホールの原因になり得ます。
WebhookはイベントによってトリガーされるHTTPコールバックですが、典型的なAPI呼び出しとは異なり、プッシュベースで非同期です。これにより、真正性の検証と配信の保証という2つの核心的な課題が生じます。このガイドでは、署名付きペイロードとスマートなリトライの両方でこれらに対処します。
Webhookとは?
Webhookはユーザー定義のHTTPコールバックです。ソースシステムでイベント(例:新しい支払い)が発生すると、イベントデータを含むHTTP POSTリクエストを指定したURLに送信します。これにより、ポーリングせずにリアルタイムで反応できます。
一般的なユースケースには、支払い通知、CI/CDトリガー、チャット統合などがあります。しかし、Webhookはパブリックインターネットを経由するため、なりすましや損失に対して脆弱です。
署名付きペイロードによるWebhookの保護
Webhookが本当にプロバイダから来たものかをどうやって確認しますか?共有シークレットでペイロードに署名することで、完全性と真正性を保証します。
HMAC署名の仕組み
プロバイダは秘密鍵を使用してリクエストボディのHMAC(例:SHA-256)を計算し、署名をヘッダー(例:X-Signature)に含めて送信します。サーバー側ではHMACを再計算し、タイミング攻撃を防ぐために定数時間比較を使用して比較します。
// Node.jsの例:Webhook署名の検証
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(payload);
const digest = hmac.digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
}
ベストプラクティス:
- Webhookエンドポイントごとに強力で一意のシークレットを使用する。
- リプレイ攻撃を防ぐために、署名付きペイロードにタイムスタンプを含める。数分以上古いリクエストは拒否する。
- 転送中のペイロードを保護するために常にHTTPSを使用する。
信頼性の高いリトライの実装
署名があっても、ネットワークの問題やダウンタイムによりWebhookの配信が失敗することがあります。プロバイダは通常、指数バックオフでリトライしますが、受信側でもリトライを処理する必要があります。
冪等性:安全なリトライの鍵
リトライは重複処理を引き起こす可能性があります。冪等性キー(多くの場合、ペイロードに含まれるかヘッダーとして提供される)を使用して、各イベントが正確に一度だけ処理されるようにします。処理済みのイベントIDを保存し、重複を無視します。
// 例:冪等なWebhookハンドラ
const processedEvents = new Set();
app.post('/webhook', (req, res) => {
const eventId = req.body.id;
if (processedEvents.has(eventId)) {
return res.status(200).send('Already processed');
}
// イベントを処理...
processedEvents.add(eventId);
res.status(200).send('OK');
});
受信側のリトライ戦略
処理が失敗した場合は、5xxステータスで応答してプロバイダのリトライをトリガーします。一時的なエラーの場合、バックオフ付きの独自のリトライキューを実装することもできます。
| シナリオ | レスポンス | アクション |
|---|---|---|
| 成功 | 200 OK | リトライなし |
| 検証エラー | 400 Bad Request | リトライなし(ペイロードを修正) |
| サーバーエラー | 500 Internal Server Error | プロバイダがリトライ |
| レート制限 | 429 Too Many Requests | プロバイダが遅延後にリトライ |
Webhookの監視とデバッグ
受信するすべてのWebhookリクエストをヘッダーとペイロードとともにログに記録します(機密データは秘匿化)。JSON Formatterのようなツールを使用してペイロードを整形表示し、検査を容易にします。配信失敗のアラートを設定し、リトライ回数を追跡します。
FAQ
署名付きWebhookペイロードとは何ですか?
署名付きペイロードには、リクエストが信頼できるソースから来たものであり、改ざんされていないことを検証する暗号署名(通常はHMAC)が含まれます。
失敗したWebhookを何回リトライすべきですか?
ほとんどのプロバイダは指数バックオフで3〜5回リトライします。受信側としては、適切なステータスコードで応答し、プロバイダにリトライを任せます。
HTTPSなしでWebhookを使用できますか?
いいえ—HTTPSはペイロードを暗号化し、中間者攻撃を防ぐために不可欠です。平文HTTPでWebhookを受け入れてはいけません。
Webhookペイロードを検査してデバッグする準備はできましたか?無料のJSON Formatterを試して、JSONデータを即座に整形および検証しましょう。