メインコンテンツへスキップ
Diditが750万ドルを調達、本人確認と不正対策のインフラを構築
Didit
ブログ一覧へ
ブログ2026年3月6日

FastifyとPostgreSQLでDidit Webhookリスナーを構築する (JA)

Node.js、Fastify、PostgreSQLを使用して、Diditのリアルタイム本人確認通知のための堅牢で安全なWebhookリスナーを構築する方法を学びます。.

By Didit更新日
building-a-didit-webhook-listener-with-fastify-postgresql.png

安全なWebhook統合HMAC-SHA256署名検証を実装することは、Didit Webhookペイロードの信頼性と完全性を確保し、アプリケーションを偽造されたリクエストから保護し、データセキュリティを維持するために不可欠です。

リアルタイムデータ処理Webhooksを利用して、本人確認セッションステータスの変更に関する即時通知を受け取り、アプリケーションが即座に反応し、ユーザーオンボーディングやリスク管理ワークフローを自動化できるようにします。

スケーラブルなデータストレージPostgreSQLを活用してWebhookデータを効率的に保存および管理し、堅牢なクエリ、監査、および既存のユーザー管理システムとの統合を可能にし、データの永続性と信頼性を確保します。

Diditのモジュラーな利点Diditのモジュラーな本人確認プラットフォームと包括的なWebhookシステムは、統合を簡素化し、開発者にクリーンなAPIとリアルタイムのデータフローを提供し、Free Core KYCとセットアップ料金なしで柔軟なAIネイティブKYCソリューションを構築できます。

Didit Webhooksとその重要性を理解する

本人確認の世界では、リアルタイムのフィードバックが最も重要です。新しいユーザーのオンボーディング、詐欺の防止、コンプライアンスの確保など、検証セッションのステータスがリアルタイムでわかることは非常に重要です。ここでWebhooksが登場します。DiditのWebhooksは、セッションの完了、失敗、さらなるアクションの必要性など、本人確認ワークフロー内で発生するイベントに関する通知を自動的に受け取る方法を提供します。

非効率的で遅延につながる可能性のあるDidit APIを常にポーリングする代わりに、Webhooksはデータを設定されたエンドポイントに直接プッシュします。このイベント駆動型アーキテクチャにより、アプリケーションは常に最新の情報を入手でき、即座の処理とスムーズなユーザーエクスペリエンスが可能になります。たとえば、ユーザーがDiditの本人確認パッシブ&アクティブな生体認証チェックを正常に完了すると、Webhookはオンボーディングフローの次のステップを即座にトリガーできます。

Diditは設定可能なWebhookバージョンを提供しており、v3はその包括的なペイロード構造により推奨される標準です。DiditビジネスコンソールまたはAPIを介して、WebhookのURL、バージョン、さらにはデータ保持ポリシーを直接設定でき、データフローとコンプライアンス義務を完全に制御できます。

Fastify Webhookリスナーのセットアップ

Fastifyは、Node.js用の高速でオーバーヘッドの低いWebフレームワークであり、高性能なWebhookリスナーを構築するのに最適です。以下に開始方法を示します。

1. プロジェクトのセットアップと依存関係

まず、Node.jsプロジェクトを初期化し、必要なパッケージをインストールします。

mkdir didit-webhook-listener
cd didit-webhook-listener
npm init -y
npm install fastify dotenv pg crypto

Didit WebhookシークレットキーとPostgreSQL接続の詳細を保存するために、.envファイルを作成します。

DIDIT_WEBHOOK_SECRET=your_didit_webhook_secret_key
DATABASE_URL=postgresql://user:password@host:port/database

DIDIT_WEBHOOK_SECRETは、Diditビジネスコンソールの「アプリ設定」またはDidit APIGET /v3/webhook/エンドポイントから取得できます。

2. Fastifyサーバーの設定

app.jsファイルを作成します。Fastifyは署名検証のために生のボディを必要とするため、WebhookルートではJSONを自動的に解析しないように設定します。

require('dotenv').config();
const fastify = require('fastify')({ logger: true });
const crypto = require('crypto');
const { Client } = require('pg');

const DIDIT_WEBHOOK_SECRET = process.env.DIDIT_WEBHOOK_SECRET;
const DATABASE_URL = process.env.DATABASE_URL;

const pgClient = new Client({ connectionString: DATABASE_URL });

// 特定のルートではボディを生のままにするために、「application/json」のコンテンツパーサーを登録します
fastify.addContentTypeParser('application/json', { parseAs: 'buffer' }, function (req, body, done) {
  if (req.raw.url === '/webhooks/didit') {
    done(null, body); // Webhookエンドポイントでは生データを残す
  } else {
    try {
      const json = JSON.parse(body.toString());
      done(null, json);
    } catch (error) {
      error.statusCode = 400;
      done(error, undefined);
    }
  }
});

fastify.post('/webhooks/didit', async (request, reply) => {
  const signature = request.headers['x-signature'];
  const timestamp = request.headers['x-timestamp'];
  const rawBody = request.body;

  if (!signature || !timestamp || !rawBody) {
    reply.code(400).send({ message: 'Missing signature, timestamp, or body' });
    return;
  }

  // 1. HMAC-SHA256署名の検証
  const expectedSignature = crypto
    .createHmac('sha256', DIDIT_WEBHOOK_SECRET)
    .update(`${timestamp}.${rawBody.toString()}`)
    .digest('hex');

  if (expectedSignature !== signature) {
    reply.code(403).send({ message: 'Invalid signature' });
    return;
  }

  // 2. タイムスタンプの検証(例:リプレイ攻撃を防ぐために5分以内)
  const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);
  if (parseInt(timestamp) < fiveMinutesAgo) {
    reply.code(403).send({ message: 'Timestamp too old' });
    return;
  }

  // 3. 検証後にJSONボディを解析
  let payload;
  try {
    payload = JSON.parse(rawBody.toString());
  } catch (error) {
    reply.code(400).send({ message: 'Invalid JSON payload' });
    return;
  }

  fastify.log.info('Received Didit webhook:', payload);

  // 4. Webhookペイロードの処理(例:DBに保存、ユーザーのステータス更新)
  try {
    await pgClient.query(
      'INSERT INTO webhooks (event_id, event_type, payload, received_at) VALUES ($1, $2, $3, NOW())',
      [payload.id, payload.event, JSON.stringify(payload)]
    );
    // 例:payload.statusに基づいてユーザーのステータスを更新
    // await pgClient.query(
    //   'UPDATE users SET verification_status = $1 WHERE didit_session_id = $2',
    //   [payload.status, payload.session_id]
    // );
    reply.code(200).send({ message: 'Webhook received and processed' });
  } catch (dbError) {
    fastify.log.error('Database error:', dbError);
    reply.code(500).send({ message: 'Internal server error' });
  }
});

const start = async () => {
  try {
    await pgClient.connect();
    fastify.log.info('Connected to PostgreSQL');
    await fastify.listen({ port: 3000, host: '0.0.0.0' });
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

PostgreSQLへのWebhookデータの保存

Webhookデータを永続化することは、監査、デバッグ、データ整合性の確保にとって非常に重要です。PostgreSQLはこのタスクに最適な堅牢なリレーショナルデータベースです。

1. データベーススキーマ

まず、Webhookイベントを保存するテーブルを作成します。このスキーマは良い出発点となります。

CREATE TABLE webhooks (
    id SERIAL PRIMARY KEY,
    event_id VARCHAR(255) UNIQUE NOT NULL, -- DiditのユニークなイベントID
    event_type VARCHAR(255) NOT NULL,
    payload JSONB NOT NULL, -- 完全なJSONペイロードを保存
    received_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

2. Fastifyとの統合

app.jsの例に示すように、pgクライアントを統合してPostgreSQLデータベースに接続し、受信したWebhookペイロードを挿入します。payload JSONB NOT NULLカラムは、Diditが導入する可能性のある新しいフィールドごとに事前定義されたスキーマ変更なしで、後で柔軟なクエリを可能にするためにJSONオブジェクト全体を保存するのに最適です。

潜在的なデータベースエラーを適切に処理することを忘れないでください。上記の例には、データベース操作のための基本的なtry-catchブロックが含まれています。

Webhookエンドポイントのセキュリティ確保

機密性の高い本人確認データを扱う場合、セキュリティは最も重要です。Diditは、受信するWebhookが正当で改ざんされていないことを確認するためにHMAC-SHA256署名を使用します。

1. HMAC署名検証

すべてのDidit Webhookリクエストには、X-SignatureX-Timestampという2つの重要なヘッダーが含まれています。X-Signatureヘッダーには、一意のWebhookシークレットと、タイムスタンプと連結された生の要求ボディを使用して生成されたHMAC-SHA256署名が含まれています。リスナーは次のことを行う必要があります。

  1. DIDIT_WEBHOOK_SECRETを取得します。
  2. X-SignatureX-Timestampヘッダーを抽出します。
  3. 署名されたペイロードを再構築します: `${timestamp}.${rawBody}`
  4. シークレットと再構築されたペイロードを使用して、独自のHMAC-SHA256署名を生成します。
  5. 生成された署名をリクエストからのX-Signatureと比較します。一致しない場合は、リクエストを拒否します。

提供されたFastifyの例は、この正確なプロセスを示しており、本物のDidit Webhookのみが処理されることを保証します。

2. タイムスタンプ検証

X-Timestampヘッダーは、リプレイ攻撃を防ぐために不可欠です。リプレイ攻撃は、攻撃者が正当なWebhookを傍受し、後で再送信するときに発生します。タイムスタンプが最近のものであること(例:現在の時刻から5分以内)を確認することで、このリスクを軽減できます。Fastifyのコードスニペットには、タイムスタンプが古すぎないことを確認するためのチェックが含まれています。

Diditが提供するもの

Diditのプラットフォームは、本人確認の統合をシームレスかつ安全にするように設計されています。当社のモジュラーアーキテクチャにより、堅牢な文書分析のための本人確認から、高セキュリティのeパスポート/eIDチェックのためのNFC検証、コンプライアンスのためのAMLスクリーニング&モニタリングまで、さまざまな本人確認チェックをプラグアンドプレイで利用できます。Webhookシステムは、このモジュール性の中心的なコンポーネントであり、常にポーリングすることなく複雑なKYCワークフローをオーケストレーションできるリアルタイムの更新を提供します。

DiditのAIネイティブなアプローチは、当社のシステムが常に学習し適応し、優れた精度と詐欺検出を提供することを意味します。明確なAPIドキュメントと開発者第一の考え方、Free Core KYCやセットアップ料金なしといった機能と相まって、簡単に始めることができます。当社のWebhooksは構造化された本人確認データを提供し、アプリケーションが検証結果にインテリジェントに反応し、グローバル規模で信頼を自動化することを可能にします。Diditの年齢推定を使用して年齢を確認する必要がある場合でも、パッシブ&アクティブな生体認証でユーザーが実在する人物であることを確認する必要がある場合でも、Diditは堅牢な本人確認ソリューションに必要なツールとリアルタイムのフィードバックを提供します。

すぐに始められますか?

Diditの実際の動作をご覧になりたいですか?今すぐ無料デモをお試しください

Diditの無料プランで、無料で本人確認を始めましょう。

本人確認と不正対策のインフラ。

KYC、KYB、取引監視、ウォレットスクリーニングを一つのAPIで。5分で統合できます。

AIにこのページの要約を依頼する
FastifyとPostgreSQLでDidit Webhookリスナーを構築.