この記事は、 NTT docomo Business Advent Calendar 2025 22日目の記事です。
SkyWayでは、2025年11月19日にWebhook機能のβ版をリリースしました。 この記事では、サービスにWebhook機能を実装する際に考慮すべき観点やアーキテクチャーについて紹介します。
はじめに
皆さまこんにちは。イノベーションセンター SkyWay DevOps プロジェクト所属の@sublimerです。
SkyWayは、ビデオ・音声通話機能を簡単にアプリケーションに実装できる、リアルタイムコミュニケーションを実現するためのプラットフォームです。 SkyWayでは、11月19日にWebhook機能のβ版をリリースしました。 Webhook機能を使うことで、ユーザーのサーバーにSkyWayで発生したイベント情報をリアルタイムで通知できるようになります。 これにより、処理の開始・終了を記録したり、エラーを即座に検知してリカバリー処理を実行するなど、イベント駆動のアーキテクチャーを容易に実現できます。
このようにWebhookは便利な機能ですが、サービス提供者として考慮すべき重要な観点がいくつかあります。 この記事では、SkyWayにWebhook機能を実装するにあたって、考慮したポイントや実際のアーキテクチャーについて紹介します。
Webhook機能を実装する際の観点
今回Webhook機能を実装するにあたって、大きく分けて以下の3つの観点について検討しました。
- セキュリティ
- 信頼性とリアルタイム性
- スケーラビリティー
1. セキュリティ
最も重視した点はセキュリティです。 Webhook機能は、ユーザーがあらかじめ設定したURLに対してSkyWayのサーバーからHTTPリクエストを送信する機能です。 そのため、以下のようなセキュリティ上のリスクが想定されます。
DoS攻撃の送信元になるリスク
悪意のある攻撃者が、攻撃対象のサーバーURLをWebhookの送信先として設定することで、SkyWayを送信元とした第三者のサーバーへのリクエストができてしまいます。 そのため、大量のリクエストが送られた場合はSkyWayがDoS攻撃の加害者になってしまうリスクがあります。
SSRF(Server Side Request Forgery)のリスク
SSRFは、攻撃者がインターネットから到達不可能な内部ネットワークのアドレスなどをリクエストの送信先として設定することで、意図しないリクエストを発生させる攻撃手法です。 クラウドサービスには、メタデータを提供する内部向けAPIなどインターネットから直接アクセスできないエンドポイントが実装されていることがあります。 悪意のある攻撃者がこれらの内部向けAPIのURLをWebhookの送信先として設定した場合、内部のエンドポイントに対して意図しないリクエストが発生するリスクがあります。
ユーザーのサーバーに対してSkyWayのWebhookを装ったリクエストが送信されるリスク
Webhookを受信するためのユーザーのサーバーは、インターネットから直接アクセスできる状態になっています。 従って、攻撃者がSkyWayからのWebhookリクエストであるかのように偽装したリクエストをユーザーのサーバーに送信することで、ユーザーのサーバーにおいて意図しない処理が実行されるリスクがあります。
2. 信頼性とリアルタイム性
Webhookで送られるデータをユーザーがログとして記録している場合、リアルタイム性は要件によって変わる一方で、データを確実にユーザーに届けられる信頼性が求められます。 また、エラーの発生をトリガーとしてリカバリー処理などを行う場合は、できるだけ遅延なくデータを届けるリアルタイム性が求められます。 このように、Webhook機能のユースケースによって、信頼性とリアルタイム性のどちらか、または両方が必要となる場合があります。
3. スケーラビリティー
SkyWayは多くのお客さまに利用されており、Webhookで送信されるイベント数もかなりの数に上ることが予想されます。 また、イベント数は時間帯によって変動し、その変化は予測が難しい場合もあります。 そのため、Webhook機能は大量のイベントを処理でき、かつ変動する負荷に柔軟に対応できるスケーラビリティーが求められます。
Webhook機能のアーキテクチャーの紹介
前述の観点についてどのように解決したのかを説明する前に、Webhook機能のアーキテクチャーの全体像を紹介します。
Webhook機能はGoogle Cloud上で構築されており、Cloud RunやCloud Tasks、Cloud NATなどのマネージドサービスを活用しています。 Webhook機能の起点は、イベントのトリガーとなるサーバーがWebhookサーバーに対してAPI呼び出しをするところから始まります。
録音・録画に関するイベントを送る場合は、以下の流れで処理が行われます。
- ①: RecordingサーバーからWebhookサーバーに対してAPI呼び出しが行われます。WebhookサーバーではユーザーのWebhook設定をチェックします。
- ②: Webhookの送信先が設定されている場合は、Cloud Tasksに対してWebhookリクエストの送信タスクを登録します。
- ③: Cloud Tasksから再度Webhookサーバーに対してAPI呼び出しが行われます。
- ④: Cloud NATを経由してユーザーのサーバーに対してWebhookリクエストが送信されます。
- ⑤: もしもWebhookリクエストがエラーになった場合はWebhookサーバーがCloud Tasksにエラーレスポンスを返すため、Cloud Tasksが自動的に③以降をリトライします。
3つの観点に対するアプローチ
それでは、前述の3つの観点に対してどのようにアプローチしたのかを説明します。
1. セキュリティ
DoS攻撃の送信元となるリスクに対しては、あらかじめWebhookの送信先として設定するURLに対する検証処理を行うことで解決しました。
Webhookの送信先の設定は、SkyWayのコンソールから行います。
- ①: ユーザーがWebhookの送信先を設定します。
- ②: コンソールからWebhookサーバーに対してWebhookの送信先設定のAPI呼び出しが行われます。
- ③: WebhookサーバーはWebhookの送信先として設定されたURLに対してチャレンジリクエストを送信します。
- ④: ユーザーのサーバーが正しいレスポンスを返せば、正規のWebhookの送信先として登録されます。
①で設定されたURLが不正な場合はチャレンジリクエストが失敗するため、Webhookの送信先として登録されることはありません。 なお、「チャレンジリクエストを大量に送ればDoS攻撃ができるのではないか」と思われるかもしれませんが、Webhookの送信先設定APIにレートリミットを設けてそのような攻撃を防止しています。
SSRFのリスクに対しては、Webhookリクエストを送る直前に送信先のドメインについて名前解決し、特定のIPアドレスの場合はリクエストを行わないようにするチェック機能を実装して解決しました。 加えて、IPアドレスでWebhookの送信先を指定することを禁止し、ドメイン名でのみ指定できるようにしています。 なお、IPアドレスのチェックとリクエストの送信を別々に行うと、チェックから送信までの間に攻撃者がDNSレコードを変更してチェックをすり抜ける、いわゆるTOCTOU (Time-of-check to time-of-use) 攻撃の脆弱性が生まれる可能性があります。これを防ぐため、名前解決で得たIPアドレスを直接利用してWebhookリクエストを送信するようにしています。
ユーザーのサーバーに対してSkyWayのWebhookを装ったリクエストが送信されるリスクに対しては、Webhookリクエストに署名を付与することで解決しました。 ユーザーは事前にWebhook用の共通鍵を設定し、Webhookリクエストにはその共通鍵を使って生成した署名を付与します。 ユーザーのサーバーはWebhookリクエストを受信した際に署名を検証することで、正当なSkyWayのWebhookリクエストであることを確認できます。 なお、署名の検証をする際に単純な文字列比較を使うとタイミング攻撃のリスクがあるため、定数時間で文字列比較する関数を使って署名の検証をするように案内しています。
2. 信頼性とリアルタイム性
一時的にユーザーのサーバーがダウンしていたとしても、できるだけWebhookリクエストが到達するようにリトライを行うようにしています。 リトライは、最初の数回は短い間隔で行い、その後は徐々に間隔を伸ばしていく指数バックオフ方式を採用しています。 これにより、ある程度のリアルタイム性を確保しつつ、ユーザーのサーバーが長時間ダウンしている場合でもWebhookリクエストを極力届けられる信頼性を実現しています。
3. スケーラビリティー
Webhook機能の中核となるWebhookサーバーにはCloud Runを利用しています。 Cloud Runはリクエスト数に応じて自動的にインスタンス数をスケールアウト・スケールインするため、変動する負荷に柔軟に対応できます。 また、リトライのロジックはWebhookサーバーには持たせず、Cloud Tasksに任せるようにしました。 これにより、Webhookサーバーをステートレスなものとし、スケーラビリティーを高めています。 Cloud Tasksのキューがボトルネックになるように思われるかもしれませんが、Cloud Tasksは複数のキューをあらかじめ作成しておき、ランダムにキューを選択することでスケールが可能です。
その他の観点
前述した3つの観点に加えて、以下のような観点についても考慮したアーキテクチャーとしました。
Webhookリクエストを送る際は、Cloud Tasksから直接ユーザーのサーバーに対してリクエストを送るのではなく、一旦Webhookサーバーを経由してリクエストを送るようにしています。 これは、以下の2つの理由によるものです。
- Cloud NATを利用して送信元IPアドレスを固定できる
- Webhookリクエストの内容を柔軟に指定できる
前述のように、署名の検証によって不正なリクエストを除外できますが、追加の対策としてIPアドレスを元にアクセス制限を行いたいというユーザーが想定されました。 Cloud TasksからのリクエストはIPアドレスが固定されないため、WebhookサーバーとCloud NATを経由してユーザーのサーバーに対してリクエストを送ることで、送信元IPアドレスを固定できるようにしました。
また、Cloud Tasksからのリクエストには、Cloud Tasksが付与するリクエストヘッダーなどが含まれています。
ユーザーのサーバーに対してWebhookリクエストを送る際に、これらの不要なヘッダーを除外したり必要なヘッダーを追加したりするために、Webhookサーバーを経由してリクエストを送るようにしています。
例えば、一般的にHTTPリクエストの送信元を示す User-Agent ヘッダーとして、SkyWayのWebhook機能では SkyWay-Webhook/1.0.0 (+https://skyway.ntt.com/) という値を設定しています。
上記の観点に加えて、Webhookサーバーを独立したコンポーネントとし、Webhook関連の情報をWebhookサーバーに集約するようにしています。 これにより、RecordingサーバーをはじめとしたSkyWayのサーバーからWebhookを送る際にWebhookサーバーのAPIを呼び出すだけでよい構成を実現しました。 イベントがWebhookリクエストの対象か、Webhookの送信先は設定済みかといった情報はWebhookサーバー側で管理するため、各サーバー側でWebhookに関する情報を持つ必要がありません。 これにより、将来的に複数のサーバーがWebhookを送りたくなった場合でも、柔軟に対応できるアーキテクチャーを実現しています。
おわりに
本記事では、SkyWayにWebhook機能を実装するにあたって、考慮した観点とそれらに対する具体的なアプローチ、およびWebhook機能のアーキテクチャーについて紹介しました。
Webhook機能は、多くのSaaS・PaaSで提供されている機能ですが、使う側ではなく作る側の立場を経験できたことは非常に貴重な経験でした。
現在のWebhook機能はβ版としての提供ですが、今年度中に対応するイベントの数を増やした上で正式版としてのリリースを目指しています。 Webhook機能はSkyWayのFreeプランでも利用可能ですので、ぜひお試しください。
以上、NTT docomo Business Advent Calendar 2025 22日目の記事でした!! それでは、明日もお楽しみに!!