
CSPジェネレーター:Content Security Policyを頭痛なしで設定する
📷 Pixabay / PexelsCSPジェネレーター:Content Security Policyを頭痛なしで設定する
Content Security PolicyでXSS攻撃を防ぐ方法。ディレクティブの設定から本番環境でのテストまで実践的に解説します。
Content Security Policy(CSP)はウェブセキュリティの世界で最も効果的なツールの一つですが、同時に最も設定が面倒なものでもあります。CSPのHTTPヘッダーを一から手書きするのは、複雑なディレクティブ構文と格闘しながら、サイトの機能を壊すかセキュリティの穴を残すかのギリギリのバランスをとる作業です。
このガイドではCSPの仕組みを徹底的に解説し、CSPジェネレーターを使って正確なヘッダーを効率よく生成する方法を紹介します。
Content Security Policyとは何か
CSPはHTTPレスポンスヘッダーで、ブラウザにどのリソース(スクリプト、スタイルシート、画像、フォント、その他のコンテンツ)を読み込んでいいかを指示します。CSPが適切に設定されていれば、攻撃者がXSS(クロスサイトスクリプティング)で悪意あるスクリプトを注入しても、そのスクリプトは承認されていないオリジンから来ているため、ブラウザが実行をブロックします。
XSSはウェブの最も危険な脆弱性の一つです。攻撃者はユーザー入力フィールド、URLパラメーター、HTMLインジェクションのある箇所などを通じて悪意あるJavaScriptを注入し、セッショントークンの盗取、フィッシングコンテンツの注入、ユーザーデータの改ざんなどを行います。
CSPはこの攻撃に対する追加の防衛層です。入力バリデーションに加えてCSPを設定することで、XSS攻撃が成功してもその影響を大幅に限定できます。
CSPヘッダーの基本構造
CSPはHTTPレスポンスヘッダーとして送信します:
Content-Security-Policy: directive1 value1 value2; directive2 value1; ...
例えば:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data: https:;
各ディレクティブはセミコロンで区切り、ディレクティブ名の後にスペースで区切った値のリストが続きます。
主要なCSPディレクティブ
default-src
他のディレクティブで明示的に指定されていないリソースタイプのフォールバックです。
default-src 'self';
'self'は現在のオリジン(プロトコル+ドメイン+ポートが同じ)のみを許可します。
script-src
JavaScriptの読み込み元を制御します。最も重要で最も慎重に設定すべきディレクティブです。
script-src 'self' https://cdn.jsdelivr.net;
よく使うソース値:
'self'- 同一オリジンのみ'none'- スクリプトをすべて禁止https://example.com- 特定のオリジンを許可'nonce-{random}'- 特定のnonceを持つインラインスクリプトを許可'strict-dynamic'- 信頼されたスクリプトがさらにスクリプトを動的に読み込むことを許可
絶対に避けるべき:本番環境での'unsafe-inline'と'unsafe-eval'。これらはCSPのセキュリティ効果をほぼ無効化します。
style-src
CSSの読み込み元を制御します。
style-src 'self' https://fonts.googleapis.com;
img-src
画像の読み込み元を制御します。
img-src 'self' data: https:;
data:はbase64エンコードされたインライン画像を許可します。https:はHTTPS経由のすべての外部画像を許可します。
font-src
フォントファイルの読み込み元を制御します。
font-src 'self' https://fonts.gstatic.com;
connect-src
fetch()、XMLHttpRequest、WebSocketなどの通信先を制御します。
connect-src 'self' https://api.example.com wss://ws.example.com;
frame-src
iframeの読み込み元を制御します。
frame-src 'none'; /* iframeを完全禁止 */
または特定のドメインのみ許可:
frame-src https://www.youtube.com;
form-action
フォームの送信先URLを制御します。
form-action 'self';
base-uri
<base>タグのURLを制限します。これはDOMベースのXSS攻撃を防ぐために重要です。
base-uri 'self';
upgrade-insecure-requests
ページ上のHTTPリクエストをすべてHTTPSに自動的にアップグレードします。
upgrade-insecure-requests;
よくある設定の落とし穴
落とし穴1:unsafe-inlineに頼る
インラインスクリプト(<script>alert(1)</script>など)を動かすために'unsafe-inline'を追加したくなりますが、これはCSPのXSS防御をほぼ無効にします。
解決策:nonceを使う。サーバーは各リクエストごとにランダムなnonce値を生成し、許可するスクリプトタグにnonce属性を付けます:
<script nonce="r4nd0m_v4lu3">
// このスクリプトは許可される
</script>
CSPヘッダー:
script-src 'nonce-r4nd0m_v4lu3';
nonce値はリクエストごとにランダムに変わるため、攻撃者には予測できません。
落とし穴2:eval()を使っているライブラリ
一部のライブラリ(古いバージョンのAngularなど)はeval()を使用するため、'unsafe-eval'が必要になります。最近のフレームワークはほとんどこの問題を解消していますが、依存ライブラリを確認してください。
落とし穴3:サードパーティスクリプトの見落とし
Google Analytics、Intercom、Stripe、HotjarなどのサードパーティスクリプトはCDNから読み込まれるため、それらのドメインをscript-srcに追加する必要があります。
script-src 'self' https://www.googletagmanager.com https://js.stripe.com;
落とし穴4:報告なしで本番環境に適用する
CSPを適切にテストせずに本番環境に適用すると、JavaScriptが動かなくなる、フォントが読み込まれない、APIコールがブロックされるなどの問題が発生します。
report-onlyモード:安全なテスト方法
本番環境でCSPをテストするための最善の方法はContent-Security-Policy-Report-Onlyヘッダーを使うことです:
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri /csp-report
このヘッダーを使うと:
- 違反があってもコンテンツはブロックされない
- すべての違反が
report-uriで指定したエンドポイントに報告される - サイトを壊さずに本番トラフィックでCSPのテストができる
報告されたデータはJSON形式で送られてきます:
{
"csp-report": {
"document-uri": "https://example.com/page",
"violated-directive": "script-src",
"blocked-uri": "https://external-site.com/script.js",
"original-policy": "default-src 'self'; script-src 'self'"
}
}
この情報を使って、許可リストに追加すべきドメインを特定できます。
実践的なCSP設定例
シンプルなスタティックサイト
Content-Security-Policy:
default-src 'self';
img-src 'self' data:;
style-src 'self' 'unsafe-inline';
font-src 'self';
form-action 'self';
base-uri 'self';
Google Analyticsを使うサイト
Content-Security-Policy:
default-src 'self';
script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com;
img-src 'self' https://www.google-analytics.com data:;
connect-src 'self' https://www.google-analytics.com;
style-src 'self';
font-src 'self';
form-action 'self';
base-uri 'self';
Google FontsとStripeを使うSaaS
Content-Security-Policy:
default-src 'self';
script-src 'self' https://js.stripe.com;
style-src 'self' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https:;
connect-src 'self' https://api.stripe.com;
frame-src https://js.stripe.com;
form-action 'self';
base-uri 'self';
SPAアプリケーション(nonce使用)
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{server_generated_nonce}' 'strict-dynamic';
style-src 'self' 'nonce-{server_generated_nonce}';
img-src 'self' data: blob:;
connect-src 'self' https://api.yourapp.com;
font-src 'self';
form-action 'self';
base-uri 'self';
upgrade-insecure-requests;
meta タグによるCSPの設定
HTTPヘッダーを設定できない場合(静的ホスティングなど)、HTMLの<meta>タグでもCSPを設定できます:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self'">
ただし、<meta>タグはHTTPヘッダーより遅く適用されるため、HTMLの最初の方(<head>内の最初の要素として)に配置することが重要です。また、frame-ancestorsやreport-uriディレクティブは<meta>タグでは使えません。
CSPジェネレーターのメリット
CSPヘッダーを手書きすることは可能ですが、以下の理由で困難です:
- ディレクティブ名のスペルミス(エラーが出ない)
- 必要なディレクティブの見落とし
- 複数のサードパーティサービスを使う場合のオリジンの管理
- report-only設定と本番設定の切り替え
CSPジェネレーターを使うと:
- UIで各ディレクティブを設定し正確なヘッダー文字列を生成
- 一般的なサードパーティサービスのプリセット
- report-only/強制適用の切り替え
- 生成されたヘッダーをコピーしてすぐにサーバー設定に貼り付け可能
CSP実装の推奨ワークフロー
- report-onlyモードで開始 -
Content-Security-Policy-Report-Onlyヘッダーで始める - 違反を収集 - 数日間、本番トラフィックで違反レポートを収集する
- ポリシーを調整 - 正当なリソースをホワイトリストに追加し、不正なものはブロックのまま
- 段階的に強制適用 - 十分なデータが集まったら
Content-Security-Policyに切り替える - モニタリングを継続 - 新機能追加時にCSP違反がないか継続的に監視する
まとめ
CSPはXSS攻撃に対する強力な防御層ですが、正しく設定するには注意が必要です。
重要なポイント:
'unsafe-inline'と'unsafe-eval'は本番環境では避ける- nonceを使ってインラインスクリプトを安全に許可する
report-uriで違反を監視し続ける- report-onlyモードで本番適用前にテストする
- サードパーティスクリプトのオリジンを
script-srcに追加する
CSPジェネレーターを使えば、このすべてのプロセスが大幅に簡単になります。正確なヘッダー構文を覚えなくても、UIで設定してコピーするだけです。