セキュリティ

Webhook URLを含むHTMLを共有するときのリスクと対策

Webhook URLを含むHTMLを外部共有すると、社内Slackチャンネルへの不正投稿やDiscord Botの乗っ取りが発生するリスクがある。AIが生成するHTMLにはこの情報が平文で含まれやすく、動作確認を終えた時点で公開してしまうケースが多い。リスクの全体像と対策の優先順位をまとめた。

なぜ危ないのか

Slack Incoming Webhook URLはトークンを含む単一のURLで、このURLに向けてHTTP POSTを送るだけでチャンネルにメッセージを投稿できる。認証ヘッダは不要で、curlでもブラウザでも送信可能なため、URLを知っているだけで誰でもチャンネルを操作できる。社内の重要な通知チャンネルのWebhook URLが漏れると、混乱させるための偽情報を簡単に流せる。

DiscordのWebhook URLが漏れた場合も同様に、そのサーバーのチャンネルに誰でも投稿できる。さらにDiscordのWebhookはメッセージ内容に制限が少なく、外部画像やリンクを含む投稿も可能なため、フィッシングリンクをDiscordコミュニティのメンバーに向けて投稿するという悪用ができる。

AIが生成するHTMLにWebhook URLが含まれている場合、そのURLがGitHubのパブリックリポジトリにコミットされると、GitHub Secret Scanningが検出するまでの間にボットにURLを収集される可能性がある。GitHubはSlackやDiscordのWebhook URLパターンを検知するシークレットスキャンを提供しているが、検知まで数秒から数分のラグがあり、その間に悪用される危険がある。

  • 相手がログインなしで開ける状態か確認する
  • PCとスマホで最低1回ずつ表示を確認する
  • 内部情報・個人情報・不要な外部送信が残っていないか見る
  • レビュー期限と修正時の差し替え方を決めておく

ソースで見る場所

HTMLのソースで通知系サービスのドメインパターンをまとめて検索する。`grep -Ein 'hooks\.slack\.com|discord\.com/api/webhooks|outlook\.office\.com/webhook|api\.telegram\.org/bot' output.html`を実行し、ヒットした行にURLのフルパスが含まれていれば即座に除去が必要だ。

JavaScriptの文字列連結でWebhook URLを組み立てているケースも確認する。`const base = 'https://hooks.slack.com/services/'`のような形でURLの一部を変数に入れ、後でつなぎ合わせるコードがある場合も問題だ。結合された完全なURLは`grep`の単純な検索では見つかりにくいため、`hooks.slack.com`・`services/`・`api/webhooks`のような部分文字列でも検索する。

設定オブジェクトやJSONリテラルの中にWebhook URLが含まれていないかも確認する。`const config = { slackUrl: 'https://...' }`のような形でオブジェクトに埋め込まれていると、コードの流れを追わないと見つけにくい。`grep -n 'slackUrl\|webhookUrl\|notifyUrl' output.html`でキーの名前を手がかりに探すと見つけやすい。

  • HTML内の外部script・form action・iframeを確認する
  • APIキーやトークンらしき文字列がないか検索する
  • 画像・CSS・JSのパスが公開後も解決できるか見る
  • noindexと認証を混同せず、必要なら両方設定する

安全に共有する設定

Webhook URLをプレースホルダーに置換したHTMLを共有する場合、プレースホルダーが一目で分かる形式(`REPLACE_WITH_YOUR_SLACK_WEBHOOK_URL`)にする。受け取ったエンジニアが検索して置換するだけで動くよう、プレースホルダーは全角文字を混ぜずすべて半角英数字で記述する。

Webhook通知の動作デモをどうしても見せたい場合は、専用のテストチャンネルと専用のWebhook URLを作成し、そのチャンネルへのアクセス権がないメンバーを招待した後にURLを共有する方法が安全だ。万が一URLが流出しても、影響がテストチャンネルの投稿だけに限定される。

ギガサイト便でHTMLを共有する際は、アクセスログを確認して予想外のアクセス元がないかを監視する。Webhook URLがプレースホルダーのままであれば動作はしないが、アクセスパターンを把握しておくことで、万が一後からURLが復元されたとしても影響範囲を判断できる。

  • HTML内の外部script・form action・iframeを確認する
  • APIキーやトークンらしき文字列がないか検索する
  • 画像・CSS・JSのパスが公開後も解決できるか見る
  • noindexと認証を混同せず、必要なら両方設定する

再発防止ルール

プロジェクトのドキュメントに「Webhook URLは絶対にHTMLファイルに直書きしない。開発時はdotenvまたは環境変数、デプロイ時はCIシークレットとして管理する」という方針を明記する。AIへのプロンプトにも同じ方針を制約として追加し、生成物が常にこの方針に従う状態を作る。

GitHub ActionsのCIでSemgrepのシークレット検出(`semgrep --config=p/secrets`)を実行するstepを追加する。SlackやDiscordのWebhook URLパターンがコードに含まれていた場合にCIが落ちるようにしておくと、マージ前に必ず発見できる。

インシデント訓練として、意図的にWebhook URLをテストコードに含めてCIが検出するかを定期的に確認する。検出から通知・対応までのフローをシミュレーションしておくことで、本番でインシデントが起きたときの対応が速くなる。

  • HTML内の外部script・form action・iframeを確認する
  • APIキーやトークンらしき文字列がないか検索する
  • 画像・CSS・JSのパスが公開後も解決できるか見る
  • noindexと認証を混同せず、必要なら両方設定する

よくある質問

GitHub Secret ScanningがWebhook URLを検出した場合、Slackからどのように通知が来ますか?

GitHub Secret ScanningがSlack Webhook URLを検出すると、GitHubのセキュリティアラートとして通知される。SlackはGitHubパートナーとして登録されており、GitHubから通知を受け取ってWebhookを自動失効させる仕組みがある(push protection機能)。

AIが生成したHTMLのWebhook URLが、実際に自社のSlackに通知が届くURLかどうかをどうやって判断しますか?

Slack管理画面の「App管理」→「カスタムインテグレーション」→「Incoming Webhook」で登録済みURLの一覧を確認する。HTMLに含まれるURLがこの一覧に含まれていれば実際に機能するURLだ。一覧になければAIが架空のURLを生成している可能性が高い。

Webhook URLをHTMLから分離してサーバー側で管理する場合、どういう設計が一般的ですか?

フロントエンドからサーバーの内部API(例:`/api/notify`)にPOSTし、サーバー側がそのWebhook URLへ中継する設計が一般的だ。Webhook URLはサーバーの環境変数に置きフロントエンドには渡さない。これによりHTMLのソースにURLが現れなくなる。

関連記事

セキュリティ

http混在を含むHTMLを共有するときのリスクと対策

http混在を含むHTMLを共有した場合のリスクを把握し、適切な対処法を選びたい方向け。ブラウザによる表示ブロックや通信傍受のリスクを具体的に示しながら、修正・代替策・共有設定の3つの観点から対策を解説します。

5分で読める
セキュリティ

XSSを含むHTMLを共有するときのリスクと対策

XSSが含まれる可能性のあるHTMLを共有するリスクを把握し、適切な対策を講じたい担当者向け。被害シナリオ、コードレベルの修正方法、CSPによる軽減策、再発防止の仕組みづくりを段階的に解説します。

5分で読める
セキュリティ

オープンリダイレクトを含むHTMLを共有するときのリスクと対策

オープンリダイレクトを含むHTMLを外部共有するリスクを理解し、修正判断と対策を迷わず行いたいチームリーダー・開発者向け。フィッシング被害の具体的なシナリオと、許可リスト実装・URL認証による二段階対策を解説する。

6分で読める
「セキュリティ」の記事をもっと見る →