2026年5月20日
2026年5月20日
WordPressのContent Security Policy(CSP)を設定する方法
はじめに
Content Security Policy(CSP)は、ブラウザがどのリソース(スクリプト・スタイル・画像など)を読み込んでよいかを制御するHTTPヘッダーです。XSS(クロスサイトスクリプティング)攻撃を大幅に困難にする強力なセキュリティ機構です。
症状・原因
- セキュリティ診断でCSPが未設定と指摘された
- XSS攻撃のリスクを軽減したい
Content-Security-Policyヘッダーがなく、ブラウザのセキュリティ機能が活用されていない- インラインスクリプトが多用されており、CSP適用に苦労している
解決手順
ステップ1:Report-Onlyモードで現状の違反を把握する
// functions.php: まずはレポートのみモードで安全にテスト
add_action('send_headers', function(): void {
// ① Report-Only モード: ブロックせず違反をレポートのみ
// WordPress の標準的なリソースを許可するCSP
$csp = implode('; ', [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com https://www.googletagmanager.com",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
"img-src 'self' data: https:",
"font-src 'self' https://fonts.gstatic.com",
"connect-src 'self' https://www.google-analytics.com",
"frame-src 'self' https://www.youtube.com https://www.google.com",
"object-src 'none'",
"base-uri 'self'",
"report-uri /wp-json/csp/v1/report",
]);
// Report-Only: ブロックせずレポートのみ(安全にテスト)
header('Content-Security-Policy-Report-Only: ' . $csp);
});
# ブラウザの開発者ツール → コンソールで CSP 違反を確認
# または report-uri.com などのサービスでレポートを収集
# 違反がなくなったら本番 CSP に切り替える
ステップ2:WordPress に適した CSP ディレクティブを設計する
// functions.php: WordPress 環境に合わせたCSPを設定
add_action('send_headers', function(): void {
// WordPress 標準 + よく使うプラグインに対応したCSP
$directives = [
// スクリプト: 自分のサイト + Google系 + インライン許可
// 理想は nonce を使うが、プラグイン互換性のため unsafe-inline も含める
"script-src 'self' 'unsafe-inline' 'unsafe-eval'"
. " https://www.google-analytics.com"
. " https://www.googletagmanager.com"
. " https://connect.facebook.net"
. " https://apis.google.com",
// スタイル: 自分のサイト + Google Fonts + インライン許可
"style-src 'self' 'unsafe-inline'"
. " https://fonts.googleapis.com",
// 画像: 自分のサイト + データURI + HTTPS全般
"img-src 'self' data: https: blob:",
// フォント
"font-src 'self' https://fonts.gstatic.com data:",
// 接続先(AJAX, Fetch)
"connect-src 'self' https://www.google-analytics.com https://stats.g.doubleclick.net",
// フレーム(YouTube埋め込み等)
"frame-src 'self' https://www.youtube.com https://www.youtube-nocookie.com https://www.google.com",
// オブジェクト(Flash等): 全て禁止
"object-src 'none'",
// フォーム送信先を自分のサイトに制限
"form-action 'self'",
// base タグのURL制限
"base-uri 'self'",
// デフォルト
"default-src 'self'",
// フレームに埋め込まれることを防ぐ
"frame-ancestors 'self'",
];
$csp = implode('; ', $directives);
header('Content-Security-Policy: ' . $csp);
});
ステップ3:nonce を使ってインラインスクリプトを安全に許可する
// functions.php: nonce ベースの CSP(より厳格な設定)
// ① CSP nonce を生成して共有
add_action('init', function(): void {
if (!isset($GLOBALS['csp_nonce'])) {
$GLOBALS['csp_nonce'] = base64_encode(random_bytes(16));
}
});
// ② script タグに nonce を付与するフィルター
add_filter('script_loader_tag', function(string $tag, string $handle): string {
$nonce = $GLOBALS['csp_nonce'] ?? '';
if ($nonce) {
$tag = str_replace('<script ', '<script nonce="' . esc_attr($nonce) . '" ', $tag);
}
return $tag;
}, 10, 2);
// ③ nonce を使った CSP ヘッダーを送信
add_action('send_headers', function(): void {
$nonce = $GLOBALS['csp_nonce'] ?? '';
if (!$nonce) return;
$csp = "default-src 'self'; script-src 'self' 'nonce-{$nonce}'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; object-src 'none'";
header('Content-Security-Policy: ' . $csp);
});
ステップ4:CSP違反のレポートエンドポイントを設置する
// functions.php: CSP 違反レポートを受け取るREST APIエンドポイント
add_action('rest_api_init', function(): void {
register_rest_route('csp/v1', '/report', [
'methods' => 'POST',
'callback' => function(\WP_REST_Request $request): \WP_REST_Response {
$body = $request->get_body();
$report = json_decode($body, true);
// ログに記録
error_log('CSP Violation: ' . wp_json_encode($report));
// 必要に応じてDBに保存やメール通知
return new \WP_REST_Response(['status' => 'received'], 200);
},
'permission_callback' => '__return_true',
]);
});
ステップ5:設定を確認する
# CSP ヘッダーが送信されているか確認
curl -sI https://example.com/ | grep -i "content-security-policy"
# ブラウザで確認(開発者ツール → Network → Response Headers)
# CSP 違反がコンソールに表示されるか確認
# オンラインツールで CSP を解析
# https://csp-evaluator.withgoogle.com/ で脆弱なCSPを検出
# WP-CLI で確認
wp eval "
\$r = wp_remote_head('https://example.com/');
echo wp_remote_retrieve_header(\$r, 'content-security-policy');
"
注意事項
- WordPress は多くのプラグイン・テーマがインラインスクリプトを使用するため、
'unsafe-inline'を完全に排除するのは難しい場合があります。まずReport-Onlyモードでテストし、違反を把握してから段階的に厳格化してください - Google Analytics・Google Tag Manager・Facebook Pixel などのサードパーティスクリプトは
script-srcに各ドメインを追加する必要があります。CDNを使用している場合はCDNのドメインも必要です - CSPを誤って設定するとサイトの機能が壊れます。必ず
Content-Security-Policy-Report-Onlyでテストしてから本番適用してください
まとめ
CSP設定は①Content-Security-Policy-Report-Onlyヘッダーで違反を把握、②WordPress標準リソース(Google Analytics・YouTube等)をscript-src・style-srcに列挙、③nonceを使いインライン許可を最小化、④/wp-json/csp/v1/reportエンドポイントで違反ログを収集、⑤curl -sIでヘッダー送信を確認・オンラインツールで評価します。