X-ThunderPhone-Signature ヘッダーに HMAC-SHA256 署名が含まれます。一度正しく
検証を実装し、同じヘルパーをすべてのハンドラーに組み込んでください。
アルゴリズム
- 生のリクエスト本文(POST した正確なバイト列)を読み取ります。
hmac_sha256(secret, body).hexdigest()を計算します。X-ThunderPhone-Signatureと定数時間で比較します。 (単純な文字列比較ではタイミング情報が漏洩します。)
, と :)、UTF-8 です。フレームワークがパース済み JSON しか公開しない場合は、
完全に同等の別の方法として、正規形式で再シリアライズして HMAC を計算できます。
使用するシークレット
シークレットはシークレットマネージャーまたは環境変数に保存し、コミットしないでください。
リファレンス実装
以下の 4 つはいずれも生のリクエスト本文を検証します。フレームワーク別の実装
ツール呼び出しの検証
エージェントが 関数ツールを直接呼び出す場合(ツールにendpoint がある場合)、設定した endpoint.headers に加えて、
リクエストには次の 2 つの ThunderPhone ヘッダーが含まれます。
X-ThunderPhone-Call-ID— 進行中の通話の数値 ID。X-ThunderPhone-Signature— リクエスト本文の完全一致するバイト列に対して 組織レベルのWebhookシークレットをキーに使用した HMAC-SHA256。
verify() ヘルパーを変更せずに使用できますが、次の 2 点に注意してください。
GET/DELETEツールには本文がありません。 引数はクエリ パラメーターとして渡され、署名は空のバイト文字列に対して計算されます。 したがって、Python ではverify(b"", sig, secret)、Node ではverify(Buffer.alloc(0), sig, secret)を使用します。クエリ文字列をハッシュ化 しないでください。- レガシーWebhookが設定されていない組織には、組織シークレットがありません。
この場合、ツール呼び出しには
X-ThunderPhone-Call-IDのみが含まれ、署名 ヘッダーは含まれません。署名用シークレットを取得するにはレガシーWebhook (PUT /v1/webhook)を設定するか、endpoint.headersを通じて独自の ヘッダーでツール呼び出しを認証してください。
endpoint のないツールが
telephony.tool / web.tool として組織Webhookに配信される場合)は、通常の
署名付きWebhookです。上記の標準手順を適用してください。両方のリクエスト形式については
関数ツールを参照してください。
よくある落とし穴
デフォルト形式で再シリアライズする
デフォルト形式で再シリアライズする
ボディを解析し、JSON ライブラリのデフォルト設定
(
, / : の後のスペース、挿入順のキー)で再出力すると、
バイト列が変わり、HMAC が破損します。生のボディを検証してください。再シリアライズが必要な場合は、
キーのソート、コンパクトな区切り文字、UTF-8 という正規形式に完全に一致させてください。フレームワークが JSON を自動解析する
フレームワークが JSON を自動解析する
Express の
express.json() ミドルウェアはボディストリームを消費するため、
生のバイト列が失われます。Webhook ルートには特に express.raw() を使用するか、
前処理ミドルウェアで生のボディをバッファリングしてください。
NestJS / Koa でも同様です。「raw body」のドキュメントを確認してください。タイミング攻撃に安全でない比較
タイミング攻撃に安全でない比較
JS の
expected === signature や Python の expected == signature は
実行時間が変動する比較です。それぞれ crypto.timingSafeEqual
または hmac.compare_digest を使用してください。パフォーマンス上の差は
ありません。ツールエンドポイントに誤ったシークレットを使用する
ツールエンドポイントに誤ったシークレットを使用する
ツールエンドポイントへの直接呼び出しは、組織レベルの Webhook
シークレット(
GET /v1/webhook)で署名されます。/v1/developer/webhook-endpoints
のエンドポイントごとのシークレットは使用しません。同じ verify()
関数を再利用できますが、ツールルートでは組織のシークレットを渡してください。GET/DELETE ツールでクエリ文字列をハッシュ化する
GET/DELETE ツールでクエリ文字列をハッシュ化する
ボディのないツールメソッドでは、署名の対象は空のバイト文字列です。これにより、リクエストボディが何であっても
生のリクエストボディを HMAC にかけるという、共通の手順を維持できます。
URL やクエリ文字列をハッシュ化しても一致することはありません。
不一致時に 401 を返さない
不一致時に 401 を返さない
検証失敗時に 200 を返すと、ハンドラーがリプレイ攻撃の
標的になります。検証に失敗した場合は、必ず 2xx 以外を返してください。
次のステップ
Webhook の概要
配信セマンティクス、再試行、送信元 IP。
Webhook エンドポイント
複数の URL を管理し、シークレットをローテーションします。
Function Tools
2 つのツール呼び出しパスと、それぞれのリクエスト形式。
ツール連携
ツールを活用する完全な連携をエンドツーエンドで構築します。