Webhooks解説:署名付きペイロードとリトライ

Backend2026-10-08TryQuickToolBox

Webhookを使って決済ゲートウェイを連携したとします。テストではすべてうまくいきますが、本番環境ではイベントが時々失われたり、重複した通知を受け取って二重請求が発生したりします。根本原因は多くの場合、署名付きペイロードとリトライの処理方法にあります。この記事では、Webhookの仕組みを説明し、堅牢で安全な連携を構築するための実践的な手順を紹介します。

Webhookとは?

Webhookはユーザー定義のHTTPコールバックです。ソースシステムでイベントが発生すると(例:決済が処理される)、指定したURLにイベントデータを含むHTTP POSTリクエストが送信されます。ポーリングとは異なり、Webhookはほぼリアルタイムでデータをプッシュするため、レイテンシとサーバー負荷を軽減できます。

ただし、Webhookには課題があります。真正性の検証、障害の処理、そして正確に一度だけの処理を保証することです。それぞれについて見ていきましょう。

署名付きペイロード:真正性の検証

Webhookエンドポイントは公開されているため、誰でも偽のリクエストを送信できます。これを防ぐために、プロバイダーは秘密鍵でペイロードに署名します。署名を検証することで、リクエストが本物であることを確認できます。

HMAC署名の仕組み

ほとんどのプロバイダーはSHA-256を使用したHMAC(Hash-based Message Authentication Code)を使います。プロバイダーはリクエストボディと共有シークレットを使って署名を計算し、ヘッダー(例:X-Signature)に含めます。あなたは自身の側で署名を再計算して比較します。

Pythonでの例:

import hmac
import hashlib

def verify_signature(payload, secret, received_signature):
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received_signature)

重要:生のリクエストボディを使用してください。パースされたJSONは使用しないでください。パースすると空白が変更され、署名が壊れる可能性があります。

よくある落とし穴

リトライ:障害を適切に処理する

エンドポイントが一時的にダウンしていたり、ネットワークの問題で失敗したりする可能性があります。信頼性の高いWebhookシステムは、指数バックオフを使って失敗した配信をリトライします。

リトライ戦略

プロバイダーは通常、非2xxレスポンスまたはタイムアウト時にリトライします。一般的なパターン:

戦略説明例
固定間隔N秒ごとにリトライ30秒ごと、最大5回
指数バックオフ試行ごとに遅延を倍にする1s, 2s, 4s, 8s...
ジッター付き指数バックオフサンダリングハードを避けるためにランダム性を追加1s ± 0.5s, 2s ± 1s...

受信側として、送信側のリトライポリシーを制御することはできませんが、エンドポイントを耐障害性のある設計にすることはできます。

受信側のベストプラクティス

  1. 素早く応答する:数秒以内に2xxを返します。処理はバックグラウンドジョブにオフロードします。
  2. 冪等にする:ペイロードの冪等キーを使って重複処理を避けます。
  3. すべてをログに記録する:デバッグとリプレイのために受信したWebhookを保存します。
  4. 失敗を監視する:繰り返しの失敗に対するアラートを設定します。

冪等性の実装

重複は発生します。レスポンスが遅かったために送信側がリトライしたり、同じイベントを誤って二度処理したりすることがあります。冪等性により、イベントを複数回処理しても1回処理した場合と同じ結果になります。

一意のイベントID(多くの場合、ペイロードまたはヘッダーで提供される)を使用し、一意制約付きでデータベースに保存します。処理前にIDが存在するか確認し、存在すればスキップします。

def process_event(event_id, data):
    if EventLog.exists(event_id):
        return  # already processed
    EventLog.create(event_id)
    # process data...

高スループットのシステムでは、競合状態を避けるために分散ロックまたはデータベーストランザクションを使用してください。

セキュリティに関する考慮事項

署名検証に加えて、以下を検討してください:

ローカルでのWebhookテスト

開発中は、Webhookを受信するために公開URLが必要です。ngrokやlocaltunnelなどのツールがローカルサーバーを公開します。あるいは、多くのプロバイダーがlocalhostにイベントを転送するCLIを提供しています。

リトライ処理をテストするために失敗をシミュレートします。意図的に500エラーを返し、プロバイダーのリトライパターンを観察してください。

FAQ

Webhook署名を検証するにはどうすればよいですか?

共有シークレットを使用したHMACを使います。生のリクエストボディのハッシュを計算し、定数時間比較関数を使って署名ヘッダーと比較します。

重複したWebhookを受信した場合はどうすればよいですか?

イベントIDを保存して冪等性を実装します。ビジネスロジックを実行する前に、イベントがすでに処理されているか確認してください。

信頼性のためにWebhookのリトライだけに頼ることはできますか?

いいえ。リトライは役立ちますが、配信を保証することはできません。重要なイベントには、Webhookとポーリングのフォールバック、またはイベントを永続化するメッセージキューを組み合わせてください。

Webhookペイロードをデバッグする際には、JSONデータを検査する必要があるかもしれません。私たちのJSON Formatterを使って、ペイロードを素早く整形して検証してください。