CSPはXSS攻撃に対する最も効果的な防御手段の一つです。ブラウザにどのリソースの読み込みを許可するかを指示することで、脆弱性があっても悪意のあるコード注入を防ぎます。
CSPとは?なぜ重要?
CSPはHTTPレスポンスヘッダーで、ブラウザが読み込み可能なリソースを制御します。
CSPの仕組み
ブラウザがCSPヘッダーを受信すると、ルールに違反するリソースをブロックします:
Browser receives HTTP response:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
Browser allows:
✅ <script src="/app.js"> (same origin = 'self')
✅ <script src="https://cdn.example.com/lib.js">
Browser blocks:
❌ <script src="https://evil.com/steal.js">
❌ <script>alert('XSS')</script> (inline = not allowed)CSPディレクティブ一覧
| ディレクティブ | 制御対象 | 例 |
|---|---|---|
| default-src | Fallback for all resource types | 'self' |
| script-src | JavaScript files and inline scripts | 'self' https://cdn.example.com |
| style-src | CSS stylesheets and inline styles | 'self' 'unsafe-inline' |
| img-src | Images (img, favicon, CSS background) | 'self' data: https: |
| font-src | Web fonts (@font-face) | 'self' https://fonts.gstatic.com |
| connect-src | XHR, fetch, WebSocket, EventSource | 'self' https://api.example.com |
| media-src | Audio and video elements | 'self' |
| frame-src | Iframes and embedded frames | 'self' https://www.youtube.com |
| object-src | Plugins (Flash, Java applets) | 'none' |
| base-uri | Base element URLs | 'self' |
| form-action | Form submission targets | 'self' |
| frame-ancestors | Who can embed this page (anti-clickjacking) | 'self' |
| upgrade-insecure-requests | Upgrade HTTP requests to HTTPS | (no value needed) |
ソース値の説明
| ソース | 意味 |
|---|---|
| 'self' | Same origin (protocol + host + port) |
| 'none' | Block all resources of this type |
| 'unsafe-inline' | Allow inline scripts/styles (reduces security!) |
| 'unsafe-eval' | Allow eval(), Function(), setTimeout(string) |
| 'strict-dynamic' | Trust scripts loaded by already-trusted scripts |
| 'nonce-abc123' | Allow specific inline script with matching nonce attribute |
| 'sha256-...' | Allow inline script matching this hash |
| https: | Allow any HTTPS resource |
| data: | Allow data: URIs (e.g., inline images) |
| blob: | Allow blob: URIs |
| *.example.com | Allow all subdomains of example.com |
段階的な実装
ステップ1: レポートオンリーモードで開始
サイトを壊さずに違反を特定:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-reportステップ3: ポリシーを構築
結果に基づいてポリシーを作成:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-ancestors 'self';
base-uri 'self';
form-action 'self';
object-src 'none';
upgrade-insecure-requests一般的なCSP設定
厳格なポリシー
Content-Security-Policy:
default-src 'none';
script-src 'self';
style-src 'self';
img-src 'self';
font-src 'self';
connect-src 'self';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
object-src 'none';
upgrade-insecure-requests中程度(典型的なSPA)
Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com wss://ws.example.com;
frame-ancestors '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 https://www.googletagmanager.com;
connect-src 'self' https://www.google-analytics.com https://analytics.google.com実装方法
Nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;Apache
Header set Content-Security-Policy "default-src 'self'; script-src 'self'"Express.js
// Using helmet middleware (recommended)
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://cdn.example.com"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
}
}));
// Or manually
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy',
"default-src 'self'; script-src 'self'");
next();
});HTMLメタタグ
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'">よくある間違い
| 間違い | 影響 | 修正 |
|---|---|---|
| スクリプトにunsafe-inline使用 | XSS保護が無効に | nonceまたはhashを使用 |
| unsafe-eval使用 | eval()を許可 | eval()を避けるよう改修 |
| script-srcにワイルドカード | 任意ドメインのスクリプト許可 | 特定ドメインをホワイトリスト |
| インラインスタイルの考慮漏れ | CSS-in-JSがブロック | style-srcにunsafe-inlineかnonce |
| レポートオンリーでのテスト省略 | サイト機能が壊れる | 必ずレポートオンリーから開始 |
| base-uri未設定 | baseタグ注入を許可 | base-uri 'self'を追加 |
FAQ
CSPはどんな攻撃を防ぎますか?
主にXSS攻撃を防ぎます。また、クリックジャッキング、データ注入、混合コンテンツ問題も防ぎます。
CSPは入力検証の代わりになりますか?
いいえ。CSPは多層防御の一つです。入力の検証とサニタイズは引き続き必要です。
インラインスクリプトでCSPを使うには?
nonce(ランダムトークン)またはhash(SHA-256)を使用します。unsafe-inlineは避けてください。
CSPはサイトを遅くしますか?
いいえ。CSPはブラウザが実行し、パフォーマンスへの影響は無視できる程度です。