チャットボットのCSP設定|ウィジェット埋め込みを安全に許可する手順
外部チャットウィジェットをCSPで安全に許可するため、script-src、frame-src、connect-srcなどの役割、依存先の棚卸し、Report-Only、操作試験、段階公開を解説します。
チャットウィジェットの埋め込みコードを追加したのに、ボタンが表示されない。開発者ツールを見ると「Refused to load」や「violates the following Content Security Policy directive」と表示される。この場面でCSPを一時的に外せば原因の切り分けには役立ちますが、その状態は安全な公開設定にはなりません。
Content Security Policy(CSP)は、ページが読み込めるスクリプト、frame、通信先、画像などをブラウザーへ伝える仕組みです。外部チャットを動かすには必要な送信元を許可します。ただし、*や広いドメインを加えるのではなく、ウィジェットが実際に使う資源を種類ごとに確認する必要があります。
作業は、現行ポリシーを保存し、ベンダーの公式資料とブラウザーの通信記録から依存先を棚卸ししたうえで、各CSPディレクティブへ必要な値だけを追加する順で進めます。その後、Report-Onlyで影響を観察し、起動だけでなく送信、再接続、画像、添付、有人導線まで試してから強制適用します。
この記事のコード例にあるhttps://widget.exampleは説明用です。Socratesを含め、実際の製品で必要なオリジンや機能別の条件は、契約中サービスの最新公式資料と自社環境の通信記録を確認してください。
CSPを無効化せず、必要な通信だけを許可する
ウィジェットは、一つのJavaScriptだけで完結するとは限りません。最初のローダーが別のスクリプトを読み、iframeを作り、その内部からAPIやWebSocketへ接続し、画像やフォントを取得することがあります。起動ボタンが表示されただけでは、会話に必要なすべての機能が動くとは判断できません。
そこで、「チャットボットのドメインを許可する」という一括作業にはせず、読み込む資源と通信の目的を表にして切り分けます。同じ事業者のサービスでも、管理画面、公開ウィジェット、API、ファイル配信でオリジンが異なる場合があります。公開ページで使わない管理画面のドメインまで許可しないようにします。
| 資源・動作 | 主に確認するディレクティブ | 確認例 |
|---|---|---|
| 外部ローダー | script-src / script-src-elem | スクリプトの正確なオリジン、nonceやhashの要否 |
| チャット画面のiframe | frame-src | iframeの実際のURLとリダイレクト先 |
| API・送信・ストリーム | connect-src | HTTPS、WebSocket、EventSourceなどの送信先 |
| アイコン・添付画像 | img-src | CDN、data URL、blob URLの利用有無 |
| 外部フォント | font-src | フォント配信元と実際に必要な書体 |
| 外部スタイル | style-src / style-src-elem | 外部CSSとインラインスタイルの要否 |
CSPは多層防御の一つであり、ウィジェット自体の安全性、データ送信、認証、アクセス制御を代替するものではありません。サーバー側で外部連携を行う場合は、受信側で必要になる署名検証や認証を確認するため、チャットボットWebhookのセキュリティ設計も参照してください。
変更前に現行ポリシーと配信箇所を特定する
まず本番ページのレスポンスヘッダーを確認し、Content-Security-PolicyとContent-Security-Policy-Report-Onlyの有無を記録します。アプリケーションのコードだけでなく、CDN、WAF、リバースプロキシ、ホスティング設定がヘッダーを追加していることもあります。HTMLのmeta http-equivで設定している場合も、その内容と対象ページを確認します。
複数のCSPが送られているとき、後から配信されたポリシーが前のポリシーを単純に上書きして緩和するわけではありません。MDNでは、複数のポリシーが資源への制限を追加すると説明されています。アプリ側で許可したのに動かない場合は、CDN側などから返された別のポリシーが通信を止めていないか確認します。
- どの公開ページにポリシーが適用されるか
- HTTPヘッダー、CDN、WAF、metaのどこで生成されるか
- 環境ごとに同じ設定が配信されているか
- nonceやhashをどの処理が発行しているか
- 違反レポートの送信先と閲覧担当者
- 直前の正常な設定へ戻す方法
変更票には、現行ヘッダーを加工せずに保存します。設定画面の断片だけでなく、ブラウザーへ実際に返った値を記録すれば、設定の重複やデプロイ後の差を比較できます。レスポンスヘッダーには環境固有情報が含まれることもあるため、社内で承認された場所へ保管してください。
ウィジェットの依存先を公式資料と実測で棚卸しする
最初にベンダーの埋め込み資料とセキュリティ資料を読み、必要なオリジンと対応機能を確認します。ただし、資料に記載された例が一つでも、利用機能や配信地域によって接続先が変わる場合があります。自社で有効にする機能を明記したうえで、テスト環境のネットワーク通信を観察します。
開発者ツールのNetworkパネルでは、記録を開始してからページを開き、ウィジェットの起動、メッセージ送信、返信受信、会話終了まで操作します。添付、画像表示、音声、有人接続、認証を使う場合は、それぞれの操作も実行します。リクエストURL、種類、開始元、状態、リダイレクト先を確認し、目的を説明できない送信先を推測で許可してはいけません。
CSP違反はConsoleでも確認できます。違反メッセージには、ブロックされたURLや適用されたディレクティブが表示されることがあります。ただし、表示された送信先を一つずつ無条件に追加する方法は適切ではありません。その通信が正規のウィジェットに必要なのか、第三者タグやブラウザー拡張機能によるものなのかを、開始元と公式資料から照合します。
| 棚卸し項目 | 記録する内容 | 判断 |
|---|---|---|
| オリジン | scheme、host、必要ならport | 広い親ドメインではなく必要な範囲か |
| 資源種別 | script、frame、fetch、WebSocket、imageなど | 対応するディレクティブは何か |
| 機能 | 起動、送信、添付、認証、分析など | 自社で利用する機能か |
| 根拠 | 公式資料、サポート回答、通信記録 | 確認日と資料の版を残したか |
| データ | 送信する項目の種類 | プライバシーや契約の確認が必要か |
第三者の外部ドメインを許可することは、その送信元から指定種類の資源を読み込める範囲を広げる判断です。サブドメイン全体のワイルドカードを要求された場合は、値を固定できない理由、実際に利用されるサブドメイン、変更通知の方法、より狭い設定の選択肢をベンダーへ確認します。
資源をCSPディレクティブへ対応付ける
script-srcは、スクリプトの読み込み元や実行条件を制御します。外部ローダーのオリジンを許可しても、ページ内のインライン初期化コードがnonceやhashなしでは実行できない場合、ウィジェットは起動しません。埋め込み方法が外部ファイルだけで完結するのか、インラインコードも必要なのかを確認します。
frame-srcは、ページが読み込めるiframeなどの送信元を制御します。チャット画面がiframeで提供される場合は、そのURLが対象です。一方、frame-ancestorsは、そのポリシーを返すページをどの親ページがframeなどへ埋め込めるかを制御します。名称は似ていますが、制御する方向が異なります。自社ページ側のframe-srcを許可しても、ウィジェット提供側が自社ドメインからの埋め込みを許可していなければ表示できない場合があります。
connect-srcは、fetch()、XMLHttpRequest、WebSocket、EventSource、sendBeacon()など、スクリプトからの接続先を制御します。MDNでは、connect-src 'self'がすべてのブラウザーでWebSocketのschemeに同じように解決されるとは限らない点も案内されています。会話ストリームがWebSocketを使う場合は、実際のwss:接続先を確認して許可候補へ追加します。
img-srcには、アイコン、アバター、会話内画像、アップロード後のプレビューが関係します。data:やblob:が必要かどうかは実装次第です。動作させるために一律で足すのではなく、どの機能が使用するのか、その許可に伴うリスクを受け入れられるかを確認します。フォントやCSSも同様に、外部配信を使う場合だけ対応するディレクティブへ加えます。
個別ディレクティブを省略すると、default-srcへフォールバックするものがあります。現在のポリシーがdefault-src 'self'だけなら、外部frameや外部接続が止まるのは想定される挙動です。ウィジェットのためにdefault-src全体を広げるのではなく、必要なframe-srcやconnect-srcへ限定して追加すると、変更の影響範囲と許可理由を明確にできます。
既存ポリシーへ最小限追記し、危険な緩和を避ける
次の例はポリシーの構造を示すためのものであり、実在するサービスの設定値ではありません。
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' 'nonce-{request-specific-value}' https://widget.example;
frame-src https://chat.widget.example;
connect-src 'self' https://api.widget.example wss://stream.widget.example;
img-src 'self' https://assets.widget.example;
object-src 'none';
base-uri 'self';
report-to csp-endpoint;
nonceは、リクエストごとに予測困難な値を発行し、許可するscript要素とヘッダーで一致させる仕組みです。上記の{request-specific-value}を固定文字列として使う例ではありません。実装時は、フレームワークや配信基盤の公式手順に従います。内容が変わらない静的なスクリプトでは、hashが適する場合もあります。
表示エラーを急いで直すために、script-src * 'unsafe-inline' 'unsafe-eval'のような広い許可へ置き換えると、サイト全体でスクリプトを実行できる範囲が必要以上に広がるおそれがあります。外部製品がunsafe-inlineやunsafe-evalを必要と説明している場合は、対象機能、必要な理由、代替の埋め込み方式、解消予定を確認し、自社のセキュリティ基準に基づいて承認します。
許可する値を決める際は、パスを含むsource expressionのブラウザー挙動やリダイレクト先も考慮します。設定例をそのままコピーせず、対象ブラウザーで実際の通信を確認してください。CSP構文の詳細は、MDNのContent-Security-PolicyリファレンスとW3Cの仕様を基準に確認します。
Report-Onlyでサイト全体への影響を観察する
MDNでは、強制適用の前にContent-Security-Policy-Report-Onlyで試す方法が案内されています。Report-Onlyでは、対象ポリシーの違反を観察できますが、そのポリシーによって資源はブロックされません。ただし、現在の強制ポリシーが別に配信されている場合は、強制側の制限も引き続き有効です。
まず、提案する新しいポリシーをテスト環境へReport-Onlyで配信します。主要ページを開いてウィジェットを操作し、検出した違反をページ、ディレクティブ、ブロック先、影響する機能に分類します。既存の分析タグ、決済、動画、認証など、チャット以外の機能に関する違反も確認対象です。
違反レポートの受信先を設ける場合、届いた内容は信頼できない入力として扱います。MDNも、CSP違反レポートを攻撃者が制御し得るデータとして適切に処理するよう注意しています。保存、表示、通知の各処理でエスケープとアクセス制御を行い、レポートへ機密情報が含まれない設計になっているか確認します。
report-toを使う場合は、Reporting-Endpointsなどの関連ヘッダーとの組み合わせが必要です。対応状況を踏まえ、report-uriを併記する例もMDNにあります。採用する方式は対象ブラウザーと自社の監視基盤に応じて決めます。また、Content-Security-Policy-Report-Onlyはmeta要素では配信できないため、レスポンスヘッダーで設定します。
起動から終了まで実操作して通信を確認する
テストは「アイコンが見えた」時点で終えてはいけません。初回表示、起動、メッセージ送信、返信受信、会話継続、切断後の再接続、閉じる、再度開く、ページ遷移、再読み込みまで試します。シングルページアプリでは、画面遷移後に二重起動したり、反対にウィジェットが消えたりすることがあるため、遷移前後の状態も確認します。
- デスクトップとスマートフォンで起動できる
- 送信と返信が成功し、ストリームやWebSocketが切れない
- 切断後に想定どおり再接続できる
- アイコン、アバター、会話内画像が表示される
- 利用する場合は添付の選択、送信、表示が動く
- 有人導線や外部リンクが正しい
- 同意やプライバシー案内が表示される
- ページ遷移、戻る操作、再読み込みで重複しない
- サインイン状態と未サインイン状態で想定どおり動く
- 主要な他機能に新しいエラーがない
- CSP違反が想定した範囲へ収束している
添付や認証を本番で使わないなら、それらの接続先を「将来使う可能性がある」という理由だけで許可しません。必要な機能を有効化する時点で、改めて変更管理と試験を行います。CSP固有の通信確認を終えた後は、チャットボット公開前のテスト項目を使って、チャット以外の導線を含む総合試験へ範囲を広げると確認漏れを防げます。
限定ページから本番へ進め、戻し方を先に用意する
Report-Onlyでの確認後は、社内限定ページやアクセスの少ない対象ページで強制ポリシーを試します。ウィジェットを最終的に全ページへ表示する場合でも、設定をページ単位などで段階的に有効化できるか確認します。サイトの重要導線に関する変更と同時に実施しなければ、問題が起きたときに原因を切り分けやすくなります。
リリース計画には、実施者、承認者、監視時間、確認ページ、異常とみなす条件、ロールバック手順を記載します。ウィジェットだけが動かない場合と、サイトの主要機能が止まる場合では、戻す判断基準が異なります。重大な影響が発生した場合は、調査を続ける前に直前の承認済みポリシーへ戻せる状態にしておきます。
ヘッダー変更がCDNにキャッシュされる場合は、反映時間とキャッシュ無効化の手順も確認します。手元のブラウザーだけで判断せず、実際に返されたレスポンスヘッダーを確認し、複数のブラウザーと別のネットワークから操作します。
公開後はベンダー側の依存先変更を管理する
ウィジェット提供者がCDN、API、WebSocketの送信先を変更すると、CSPによって表示や送信が突然止まる可能性があります。契約中サービスの変更通知を誰が受け取り、どの期限までに影響を確認するかを運用台帳へ記録します。
定期確認では、現在許可しているオリジンが引き続き必要かも見直します。廃止した機能や旧配信先の許可を残し続けず、通信記録と公式資料を根拠に削除します。sourceの追加だけでなく削除も変更管理の対象とし、削除後には同じ操作による回帰試験を行います。
| 変更のきっかけ | 確認内容 | 証跡 |
|---|---|---|
| ベンダー通知 | 新旧オリジン、切替日、対象機能 | 公式通知、影響確認、承認 |
| 機能追加 | 新しい資源、送信データ、ディレクティブ | 要件、通信記録、試験結果 |
| CSP違反増加 | 正規通信か、攻撃・誤設定・拡張機能か | 分類、対応、除外理由 |
| 機能廃止 | 不要になった許可を削除できるか | 削除差分、回帰テスト |
CSPエラーとCORSエラーは別の仕組みによるものです。ブラウザー上の見え方が似ていても、ConsoleとNetworkの情報から、ブラウザーのCSPが資源や接続を拒否したのか、接続先サーバーのCORS応答が自社オリジンを許可していないのかを切り分けます。CSPを変更しても、サーバー側が自社オリジンをCORSで許可していなければ通信は成功しません。反対にCORSを広げても、CSPで止められた資源は読み込めません。
変更票に残す最小項目
- 対象ページと環境
- 現在のCSPと配信元
- 追加・削除するディレクティブとsource
- 各sourceが必要な機能と公式根拠
- 送信されるデータの種類
- Report-Onlyの観察期間と結果
- 実施した操作テストと対象ブラウザー
- 他機能への影響確認
- 承認者、実施日時、監視担当
- ロールバック条件と手順
- 次回見直し日とベンダー通知の受信者
これらを記録しておけば、将来エラーが発生したときに「なぜこのドメインを許可したのか」を追跡できます。理由が分からない許可は放置せず、対象機能の担当者と必要性を確認します。セキュリティ設定では制限の厳しさだけでなく、変更理由を説明でき、継続して見直せる状態を保つことも重要です。
埋め込み条件を確認してから公開する
チャットウィジェットのCSP設定は、利用する機能と現在のサイト構成によって変わります。SocratesのWeb埋め込みを検討する場合も、対象ページ、現行CSP、利用機能、許可候補となる通信先を整理したうえで、最新の正式な接続要件をご確認ください。
チャットボットのCSP設定でよくある質問
チャットボットがCSPで表示されない場合、どこを確認しますか?
最初にブラウザーのConsoleでCSP違反を確認し、Networkで失敗したリクエストのURLと開始元を照合します。外部ローダーはscript-src、iframeはframe-src、APIやWebSocketはconnect-src、画像はimg-srcを主に確認します。ただし、エラーに表示された送信先をそのまま許可せず、利用中サービスの最新公式資料と照合してください。
CSPへワイルドカードやunsafe-inlineを追加してもよいですか?
表示を急いで広い許可を追加すると、CSPが制限する範囲を必要以上に弱めるおそれがあります。まず資源ごとの必要性を確認し、正確なオリジン、nonce、hashなど、利用できる範囲で狭い方法を検討します。製品が広い許可を要求する場合は、必要な理由、対象機能、代替策、解消予定をベンダーへ確認し、自社の基準に基づいて承認します。
frame-srcとframe-ancestorsの違いは何ですか?
frame-srcは、自社サイトのページがどの送信元のiframeなどを読み込めるかを制御します。frame-ancestorsは、そのポリシーを返すページをどの親サイトがframeなどへ埋め込めるかを制御します。外部チャットでは、自社ページ側のframe-srcと、提供側ページの埋め込み許可の両方が関係する場合があります。