Content Security Policyジェネレーター
Content-Security-Policyヘッダーを生成します。
Build a Content-Security-Policy. Common keywords: 'self' 'none' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' data: https: blob:
概要
Content-Security-Policy は、どのソースからリソースを読み込んでよいかをブラウザに 伝えるものです。実用上の価値は名前が示すより狭く、CSP はクロスサイト スクリプティングを修正しません。封じ込めます。出力エスケープをすり抜けて 注入が成立したとき、注入されたスクリプトの実行を止め、盗んだものを攻撃者の サーバーへ送るのを止めるのが厳格なポリシーの役割です。
ヘッダはセミコロン区切りのディレクティブの並びで、それぞれがリソース種別と 許可するソースを指定します。このツールはディレクティブごとに入力欄を用意し、 妥当な初期ポリシーを埋め、入力に応じて組み立てたヘッダを表示します。
使い方
- 初期状態のポリシー(
default-src 'self'・object-src 'none'・base-uri 'self'・frame-ancestors 'none')から始めます。自前のアセットを配信するサイトの 妥当な下限です。 - 実際に必要なオリジンをディレクティブごとに足します。複数のソースは空白で 区切ります。
- 不要なディレクティブは空のままにします。空のディレクティブは
default-srcに フォールバックします。 - ヘッダをコピーし、まず
Content-Security-Policy-Report-Onlyとして配信します。 違反レポートを読み、ポリシーを直してから、強制するヘッダ名に切り替えます。
ソースキーワード
| キーワード | 意味 |
|---|---|
'self' | 文書自身のオリジン(スキーム・ホスト・ポートが同じ) |
'none' | 何も許可しない。単独で指定したときだけ意味を持つ |
'unsafe-inline' | インラインの <script> / <style> とインラインイベントハンドラを許可 |
'unsafe-eval' | eval・new Function・setTimeout の文字列引数を許可 |
'strict-dynamic' | 既に信頼されたスクリプトが生成したスクリプトを信頼する。そのディレクティブのホスト許可リストは無視される |
data: | data: URI を許可。img-src では妥当、script-src では危険 |
https: | HTTPS の任意のオリジン。広すぎるので、通常はポリシーを絞る余地がある印 |
blob: | blob: URL を許可。生成したコードから Web Worker を作る場合に必要 |
ハッシュ('sha256-…')と nonce('nonce-…')が 'unsafe-inline' の厳格な
代替です。ハッシュは内容が変わらない特定のインラインスクリプトを対象とし、
静的生成のサイトに向きます。nonce はレスポンスごとの乱数で、サーバー
レンダリングのページに向きます。静的ファイルのホスティングでは nonce は
使えません。リクエストごとに生成する箇所が存在しないためです。
間違えやすいディレクティブ
base-uri は default-src の対象外です。これが無いと、注入された
<base href> タグ 1 つで、ページ上のすべての相対 URL(script タグを含む)を
攻撃者のホストへ向けられます。スクリプトを 1 行も注入せずにです。'self' か
'none' を指定してください。
form-action も default-src の対象外です。これが無いと、注入された
フォームが利用者の入力を別のオリジンへ送信できます。
frame-ancestors は X-Frame-Options の置き換えです。両者が食い違う場合、
現代のブラウザは CSP に従うので、古いヘッダだけを設定していると、新しい
ブラウザは意図した制約を何も受けていないことになります。
object-src 'none' は明示する価値があります。プラグインコンテンツは
レガシーな実行経路で、新規サイトに正当な用途はありません。
connect-src は忘れられがちなものです。fetch・XHR・WebSocket・
sendBeacon を制御します。つまり注入されたスクリプトがデータを持ち出す
経路そのものです。script-src を締めて connect-src を開けたままにすることは、
閉じるつもりだった扉を開けておくことです。
例
第三者スクリプトを使わず自前のアセットを配信する静的サイト:
default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none';
form-action 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:;
font-src 'self'; connect-src 'self'; upgrade-insecure-requests
同じサイトに計測タグを 1 つ足す場合。https: ではなく必要なオリジンだけを
許可します:
script-src 'self' https://www.googletagmanager.com;
connect-src 'self' https://www.google-analytics.com
違反レポートの収集
Report-Only モードは、レポートを読まなければ意味がありません。仕組みは 2 つあり、 ブラウザの対応状況が分かれるため、移行期は両方送るのが普通です。
report-uri /csp-report は古いディレクティブです。非推奨ですが対応範囲は
今も最も広く、ブロックされたリソース・ブロックしたディレクティブ・文書の URL を
記述した JSON を POST します。
report-to が置き換えです。別の Reporting-Endpoints レスポンスヘッダで
設定したレポートグループを指定し、CSP・非推奨・介入のレポートを 1 つの
エンドポイントでまとめて受けられます。
どちらを使うにしても、ノイズは前提として見込んでください。ブラウザ拡張は
ページにスクリプトとスタイルを注入し、その違反はレポート上では自分のものと
区別できません。信号になるのは、同じ文書 URL・同じディレクティブで多数の
異なる利用者から上がってくる違反です。chrome-extension: スキームを指す
単発の blocked-uri は、誰かのパスワードマネージャです。
どちらのディレクティブも <meta> タグでは使えません。レポートには実際の
HTTP ヘッダが必要です。
注意事項
upgrade-insecure-requests は、http:// のサブリソースへのリクエストを
送信前に https:// へ書き換えます。混在コンテンツを持つページの移行を
助けるもので、URL を直す代わりにはならず、他サイトへの遷移には適用されません。
style-src の 'unsafe-inline' は最後まで残ることが多く、そして残す価値が
あることも多いものです。インラインの style 属性はハッシュで許可できず
('unsafe-hashes' に加えて属性の値ごとにハッシュが必要になります)、CSS 注入は
スクリプト注入よりはるかに狭い問題です。先に script-src へ労力を割く方が
費用対効果で勝ちます。
強制する前に Content-Security-Policy-Report-Only で配信してください。
1 つ厳しすぎるポリシーは緩やかに劣化しません。強制するブラウザを使う全訪問者に
対してページを静かに壊し、自分のテストではなく利用者から知らされることになります。
稼働中のサイトが現在何を送っているか確認したいときは、 HTTP ヘッダチェッカー が任意の URL のレスポンスヘッダを表示します。