⌘K でツールを切替
CSP

Content Security Policyジェネレーター

Content-Security-Policyヘッダーを生成します。

local
csp-generator

Build a Content-Security-Policy. Common keywords: 'self' 'none' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' data: https: blob:

§01 このツールについて

概要

Content-Security-Policy は、どのソースからリソースを読み込んでよいかをブラウザに 伝えるものです。実用上の価値は名前が示すより狭く、CSP はクロスサイト スクリプティングを修正しません封じ込めます。出力エスケープをすり抜けて 注入が成立したとき、注入されたスクリプトの実行を止め、盗んだものを攻撃者の サーバーへ送るのを止めるのが厳格なポリシーの役割です。

ヘッダはセミコロン区切りのディレクティブの並びで、それぞれがリソース種別と 許可するソースを指定します。このツールはディレクティブごとに入力欄を用意し、 妥当な初期ポリシーを埋め、入力に応じて組み立てたヘッダを表示します。

使い方

  1. 初期状態のポリシー(default-src 'self'object-src 'none'base-uri 'self'frame-ancestors 'none')から始めます。自前のアセットを配信するサイトの 妥当な下限です。
  2. 実際に必要なオリジンをディレクティブごとに足します。複数のソースは空白で 区切ります。
  3. 不要なディレクティブは空のままにします。空のディレクティブは default-src に フォールバックします。
  4. ヘッダをコピーし、まず Content-Security-Policy-Report-Only として配信します。 違反レポートを読み、ポリシーを直してから、強制するヘッダ名に切り替えます。

ソースキーワード

キーワード意味
'self'文書自身のオリジン(スキーム・ホスト・ポートが同じ)
'none'何も許可しない。単独で指定したときだけ意味を持つ
'unsafe-inline'インラインの <script> / <style> とインラインイベントハンドラを許可
'unsafe-eval'evalnew FunctionsetTimeout の文字列引数を許可
'strict-dynamic'既に信頼されたスクリプトが生成したスクリプトを信頼する。そのディレクティブのホスト許可リストは無視される
data:data: URI を許可。img-src では妥当、script-src では危険
https:HTTPS の任意のオリジン。広すぎるので、通常はポリシーを絞る余地がある印
blob:blob: URL を許可。生成したコードから Web Worker を作る場合に必要

ハッシュ('sha256-…')と nonce('nonce-…')が 'unsafe-inline' の厳格な 代替です。ハッシュは内容が変わらない特定のインラインスクリプトを対象とし、 静的生成のサイトに向きます。nonce はレスポンスごとの乱数で、サーバー レンダリングのページに向きます。静的ファイルのホスティングでは nonce は 使えません。リクエストごとに生成する箇所が存在しないためです。

間違えやすいディレクティブ

base-uridefault-src の対象外です。これが無いと、注入された <base href> タグ 1 つで、ページ上のすべての相対 URL(script タグを含む)を 攻撃者のホストへ向けられます。スクリプトを 1 行も注入せずにです。'self''none' を指定してください。

form-actiondefault-src の対象外です。これが無いと、注入された フォームが利用者の入力を別のオリジンへ送信できます。

frame-ancestorsX-Frame-Options の置き換えです。両者が食い違う場合、 現代のブラウザは CSP に従うので、古いヘッダだけを設定していると、新しい ブラウザは意図した制約を何も受けていないことになります。

object-src 'none' は明示する価値があります。プラグインコンテンツは レガシーな実行経路で、新規サイトに正当な用途はありません。

connect-src は忘れられがちなものです。fetchXHR・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 のレスポンスヘッダを表示します。

FAQ
ポリシーの妥当性を検証してくれますか?
いいえ。入力したフィールドからヘッダ文字列を組み立てるだけで、指定したソースに到達できるかや、サイトがまだ動くかは確認しません。信頼できる検証は実サイトでの Report-Only モードだけです(下記)。
ハッシュを足すと 'unsafe-inline' が無視されるのはなぜですか?
仕様どおりの動作で、不具合ではありません。script-src にハッシュか nonce が 1 つでも含まれると、それを理解するブラウザは 'unsafe-inline' を完全に無視します。古いブラウザには緩いキーワードを、新しいブラウザには厳格なリストを与えるための、意図された移行経路です。
frame-src と frame-ancestors の違いは何ですか?
frame-src は自分のページが何を埋め込めるかを制御します。frame-ancestors は誰が自分のページを埋め込めるかを制御し、X-Frame-Options の CSP における置き換えです。ほとんどのディレクティブと違い default-src の対象外です。
他のディレクティブを全部書けば default-src は不要ですか?
書く価値はあります。default-src は書かなかった fetch 系ディレクティブのフォールバックで、これには出荷後に仕様へ追加されたものも含まれます。'self' にしておけば、将来のディレクティブが開いた状態ではなく閉じた状態で失敗します。
完成したヘッダはどこに置きますか?
HTTP レスポンスヘッダとして、できれば CDN か Web サーバー側で、全レスポンスに適用されるように置きます。<meta http-equiv> でも動きますが frame-ancestors と report-uri は表現できず、パーサがそこに到達した時点からしか効きません。