CSP ツール
実務のContent-Security-Policy: 各ディレクティブが何を管轄するか、source expression と nonce / hash の照合規則、Report-Only での段階導入と壊れやすい箇所を、確認用ツールとあわせて解説します。
1 ツール
ポリシーの実体
Content-Security-Policy はレスポンスヘッダーで、各ディレクティブが source expression
のリストを持ちます。サブリソース取得・インライン実行・フォーム送信・frame埋め込みの前に
参照され、一致がなければリクエストは発生せず違反として報告されます。
照合単位はオリジン(scheme+host+port)で、'self' は同一オリジンのみ。CDNのホストも自身の
サブドメインも含みません。強度は最も緩い抜け道で決まり、script-src 'self' 'unsafe-inline'
は注入者にscriptタグを渡すのと同義です。CSPヘッダーが複数あれば論理積で合成されます。
ディレクティブ早見表
| ディレクティブ | 管轄 | default-src継承 |
|---|---|---|
script-src | scriptタグ・eval・インラインハンドラ | する |
connect-src | fetch・XHR・WebSocket・sendBeacon | する |
style-src / img-src / font-src / media-src | style・画像・font・音声動画 | する |
object-src / frame-src / worker-src | object・埋め込み文書・worker | する |
base-uri / form-action / frame-ancestors | baseタグの値・送信先・埋め込み許可元 | しない |
sandbox / require-trusted-types-for / report-to | sandbox・DOM XSS sink・レポート先 | しない |
要点は右列で、default-src 'self' だけでは baseタグ乗っ取り・フォーム持ち出し・
クリックジャッキングが素通りします。
source expression の規則
| 表記 | 一致するもの | 注意点 |
|---|---|---|
'self' / 'none' | 文書と同一の scheme+host+port / 何にも一致しない | サブドメインは含まない。'none' は他の値と併記した時点で無意味 |
https: | そのschemeの任意のホスト | 世界中のCDNが許可対象になる |
https://cdn.example.com | そのオリジン(ポートはscheme既定) | path付きで書いてもリダイレクト後は検査されない |
*.example.com / * | 任意の深さのサブドメイン / 任意のホスト | example.com 自体は含まない。* に data:・blob: は含まれない |
'nonce-…' | 一致する nonce 属性を持つ要素 | 128bit以上の乱数を応答ごとに再生成 |
'sha256-…' | バイト列のハッシュが一致するインラインコード | 空白1文字の差でハッシュが変わる |
'strict-dynamic' | 信頼済みスクリプトが実行時に生成したスクリプト | 同ディレクティブのhost/scheme指定は無視される |
'unsafe-inline' | 任意のインラインscript / style | nonceかhashが1つでもあると無視される |
'unsafe-eval' / 'unsafe-hashes' | eval・new Function / onclick・style 属性へのhash適用 | 限定版が 'wasm-unsafe-eval' |
Report-Only での段階導入
候補はまず Content-Security-Policy-Report-Only で配信します。評価は同一でブロックせず、
強制ポリシーと並行配信できます。収集口は report-uri か report-to(別途
Reporting-Endpoints が必要)。レポート送信は connect-src の対象外です。
クロスオリジンの blocked-uri はオリジンまで丸められるため、'report-sample' を足し
effective-directive で集計します。
ツールの使い分け
稼働中サイトの論点は「実際に配信されているポリシー」。HTTPヘッダー
は api.sitekits.dev 経由でステータス・リダイレクト数・全ヘッダーを返します(本文は取得
せず、内部アドレスはSSRF拒否)。CDNの書き換えもここで分かります。これから書くなら
CSPジェネレーター。ディレクティブ欄14個に加えて既定でONの
upgrade-insecure-requests チェックボックスがあり、初期値は default-src 'self'; frame-ancestors 'none'; base-uri 'self'; object-src 'none' の堅めのベースライン。
つまり何も触らなくても、これに upgrade-insecure-requests が付いたヘッダーが出ます。
組み立ては入力のたびにブラウザ内で再構築。欄にない report-to・sandbox・
require-trusted-types-for は手で追記します。
許可リスト作りは棚卸しです。HARを HARビューアー で一覧し、不明なURLを
URLパーサー で scheme+host+port に落とし、共有前に
HARサニタイザー を通します(Cookieや Authorization を含むため)。
差分は テキスト比較、csp-report は
JSONフォーマッター。REST APIテスター は
ブラウザから対象へ直接送信し(sitekits非経由)、適用されるのは自サイトではなくこのツール
ページのポリシー(connect-src を 'self' https: に緩和)です。ここで通るのに自サイトで
失敗するなら、疑うべきは自分のヘッダー。ただし原因の特定まではできません。connect-src
によるブロックもCORS拒否も fetch の TypeError になり、本ツールの表示は両方をまとめた
1種類のメッセージだけです。関連: HTTPハブ・
セキュリティハブ・セキュリティ職向け。
よくある破損パターン
nonce導入で 'unsafe-inline' が失効する
自前でscriptタグを注入するタグマネージャーやウィジェットが止まります。解は
'strict-dynamic'。
hashは16進ではなくbase64
ハッシュ生成 の16進出力を Base64 に通しても別値です。 値はコンソールエラーから取ります。
固定値のnonceは 'unsafe-inline' と同義
応答ごとの再生成が必須で、テンプレート即値やHTMLのみキャッシュは推測可能です。 UUIDジェネレーター は手動確認用まで。
metaタグではCSPの半分が表現できない
frame-ancestors・sandbox・report-uri・Report-Only は meta http-equiv で無視され、
効くのはそのタグ以降だけです。