Ruby on RailsにおけるDiditイベント用の冪等なWebhookコンシューマー (JA)
堅牢なWebhookコンシューマーの構築は、特にDiditのような本人確認プラットフォームからのリアルタイムイベントにおいて、信頼性の高いデータ処理のために不可欠です。.

データ整合性の確保冪等性は、Webhookイベントを確実に処理し、重複するアクションを防ぎ、アプリケーションの一貫した状態を維持するために不可欠です。
Webhook署名の活用Webhook署名を常に検証し、受信リクエストの信頼性と整合性を確認することで、改ざんやなりすましから保護します。
一意のイベントIDの利用Webhookペイロードで提供される一意のイベントIDを保存およびチェックして、重複配信を効果的に検出し、破棄します。
Diditの堅牢なWebhookシステムDiditは、HMAC署名と一意のイベントIDを備えた安全でバージョン管理されたWebhookを提供し、冪等なコンシューマーの実装を簡素化し、重要な本人確認ワークフローの信頼性の高いイベント配信を保証します。
Webhook冪等性の課題
Webhookは、サービス間のリアルタイム通信のための強力なメカニズムであり、アプリケーションが別のシステムで発生するイベントに即座に反応することを可能にします。しかし、Webhookの分散型という性質上、イベントが複数回配信されることがあります。ネットワークの不具合、タイムアウト、または再試行により、重複するWebhookペイロードが発生する可能性があります。適切な処理がなければ、これらの重複は、重複レコードの作成、冗長なアクションのトリガー、データの破損など、アプリケーションに重大な問題を引き起こす可能性があります。
ここで冪等性が重要になります。冪等な操作とは、1回実行しても複数回実行しても同じ結果を生成するものです。Webhookコンシューマーにとって、これは、Webhookペイロードが複数回受信されたとしても、特定のイベントを1回だけ処理するようにシステムを設計することを意味します。Diditのようなプラットフォームからの本人確認結果のような機密データを扱う場合、冪等性を確保することは単なる良い習慣ではなく、データ整合性とシステム信頼性を維持するために不可欠です。
セキュリティと信頼性のためのWebhook署名の検証
Webhookペイロードを処理する前に、最初で最も重要なステップは、その信頼性を検証することです。これにより、Webhookが本当に意図した送信元(例:Didit)から発信されたものであり、そのコンテンツが転送中に改ざんされていないことが保証されます。例えば、DiditのWebhookには、共有秘密鍵を使用して生成されたHMAC署名がリクエストヘッダーに含まれています。
Ruby on Railsアプリケーションでは、Diditアカウントから共有秘密鍵を取得する必要があります(ビジネスコンソールまたはAPIを介してプログラムでアクセスできます)。Webhookが到着すると、リクエストボディと秘密鍵を使用して独自のHMAC署名を計算します。この計算された署名は、Webhookヘッダーで提供された署名と比較されます。一致しない場合、リクエストは直ちに拒否されるべきです。
class DiditWebhooksController < ApplicationController
skip_before_action :verify_authenticity_token
def create
# 環境変数から共有秘密鍵を取得
secret = ENV['DIDIT_WEBHOOK_SECRET']
payload = request.body.read
signature = request.headers['X-Didit-Signature'] # または類似のヘッダー名
unless verify_signature(payload, signature, secret)
head :unauthorized
return
end
# 検証後にWebhookペイロードを処理
process_didit_event(JSON.parse(payload))
head :ok
end
private
def verify_signature(payload, signature, secret)
digest = OpenSSL::Digest.new('sha256')
hmac = OpenSSL::HMAC.hexdigest(digest, secret, payload)
ActiveSupport::SecurityUtils.secure_compare("sha256=#{hmac}", signature)
end
def process_didit_event(event_data)
# ... 処理の実装 ...
end
end
Diditは、Webhook構成の一部としてsecret_shared_keyを提供することでこれを簡素化します。これはAPIを介して取得したり、必要に応じてローテーションしたりできます。この安全なメカニズムは、ID検証や生体認証チェックの結果など、結果の整合性が最重要視される本人確認ワークフローにとって不可欠です。
一意のイベント識別子による冪等性の実装
Webhookの信頼性を検証したら、次のステップは冪等性を確保することです。Diditを含むほとんどの適切に設計されたWebhookシステムは、各イベントに一意の識別子を提供します。このIDは、重複処理を検出して防止するために不可欠です。DiditのWebhook(特に推奨されるv3)の場合、各イベントペイロードにはこの目的で使用できる一意のIDが含まれています。
この戦略は、これらのイベントIDをデータベースに保存し、処理する前にそれらに対してチェックすることです。一般的なパターンには、EventLogまたはWebhookEventモデルの作成が含まれます。
# db/migrate/YYYYMMDDHHMMSS_create_webhook_events.rb
class CreateWebhookEvents < ActiveRecord::Migration[7.x]
def change
create_table :webhook_events do |t|
t.string :event_id, null: false, index: { unique: true }
t.string :event_type
t.jsonb :payload
t.string :status, default: 'pending'
t.timestamps
end
end
end
Webhookが到着したとき:
- ペイロードから一意の
event_idを抽出します。 - この
event_idで新しいWebhookEventレコードを作成しようとします。 - 一意制約違反のために作成が失敗した場合(つまり、
event_idがすでに存在する場合)、それは重複であり、安全に無視するか、そのようにログに記録することができます。 - 作成が成功した場合、イベントの処理に進み、それに応じてステータスをマークします。
class DiditWebhooksController < ApplicationController
# ... (上記と同様の署名検証) ...
def create
# ... (署名検証) ...
event_data = JSON.parse(payload)
event_id = event_data['id'] # 'id'がDiditからのユニークなイベント識別子であると仮定
# アトミック性を保証するためにトランザクションを使用
ActiveRecord::Base.transaction do
webhook_event = WebhookEvent.find_or_initialize_by(event_id: event_id)
if webhook_event.persisted? # 既に存在する場合、それは重複
Rails.logger.info "重複するWebhookイベントを受信しました: #{event_id}"
head :ok
return
end
webhook_event.event_type = event_data['type']
webhook_event.payload = event_data
webhook_event.status = 'processing'
webhook_event.save!
# 時間のかかるタスクはバックグラウンドジョブでイベントを処理
DiditEventProcessorJob.perform_later(webhook_event.id)
head :ok
end
rescue ActiveRecord::RecordNotUnique # event_idの競合状態を処理
Rails.logger.warn "Webhookイベントの競合状態が検出されました: #{event_id}。無視します。"
head :ok
rescue JSON::ParserError
head :bad_request
rescue => e
Rails.logger.error "Webhook処理エラー: #{e.message}"
head :internal_server_error
end
end
このアプローチと、実際の処理のためのバックグラウンドジョブを組み合わせることで、Webhookエンドポイントが迅速に応答し、送信元からの再試行を防ぎながら、重複を確実に処理します。
競合状態とトランザクションの処理
一意のインデックスがあっても、2つの同一のWebhookがほぼ同時に到着した場合、競合状態が発生する可能性があります。両方が最初のコミットを行う前に新しいWebhookEventレコードを作成しようとするかもしれません。これを軽減するには:
- データベーストランザクションの使用:
find_or_initialize_byとそれに続く処理ロジックをデータベーストランザクション内にラップします。これにより、操作全体が成功するか失敗するかのいずれかが保証され、データの一貫性が維持されます。 RecordNotUniqueの処理:ActiveRecord::RecordNotUnique例外をキャッチする準備をしてください。新しいWebhookEventを保存しようとしたときにこの例外が発生した場合、それは別のプロセスがすでにイベントを挿入している競合状態を示しており、安全に重複として扱うことができます。
コアアプリケーションデータを変更する操作の場合、トランザクションをそれらの変更をカバーするように拡張することが重要です。または、少なくともイベントを処理するバックグラウンドジョブが、変更するアプリケーションデータに対して独自の冪等性チェックを実装していることを確認する必要があります。
Diditの貢献
Diditは、信頼性とセキュリティを念頭に置いて設計されたAIネイティブな開発者ファーストのIDプラットフォームであり、堅牢なWebhookコンシューマーの実装を容易にします。当社のモジュラーアーキテクチャは、クリーンなAPIと、本質的に冪等な処理をサポートするように設計された安全なWebhookを提供します。
- 安全なWebhook: DiditのWebhookは、強力なHMAC署名(管理およびローテーション可能な
secret_shared_keyを使用)を提供し、すべてのイベントの信頼性と整合性を保証します。冪等性のこの重要な最初のステップは組み込まれています。最適なペイロード構造のためにwebhook_version(v3を推奨)を指定することもできます。 - 一意のイベント識別子: すべてのDidit Webhookイベントには一意の識別子が含まれており、上記で説明した重複排除ロジックを簡単に実装できます。
- 設定可能なデータ保持: Diditを使用すると、検証データの保存期間を制御できます。ビジネスコンソールまたはAPIを介して、データ保持ポリシーを1か月から10年、または無制限のnullに設定できます。これにより、データフットプリントを管理しながら(GDPRなどの)コンプライアンス要件を満たすことができます。これは、Webhookコンシューマーがイベントログをどのように保存および管理するかにも関連します。
- 無料のCore KYCとモジュラー設計: Diditは無料のCore KYCを提供しており、初期費用なしでWebhookコンシューマーの構築とテストを開始できます。当社のモジュラー設計により、ID検証(書類チェック用)、パッシブ&アクティブ生体認証(不正防止用)、または年齢推定(年齢確認用)などの特定の本人確認製品を簡単に統合し、Webhookを介してリアルタイムの更新を受け取ることができます。
Diditの堅牢で安全なWebhookシステムを活用することで、開発者はアプリケーションのコアロジックに集中し、受信イベントのセキュリティと重複排除の複雑さに煩わされることなく、より回復力があり信頼性の高い本人確認ワークフローを実現できます。
準備はできましたか?
Diditの動作をご覧になりませんか?今すぐ無料デモを入手してください。
Diditの無料ティアで無料で本人確認を開始しましょう。