2026年5月20日

2026年5月20日

WordPressのセキュリティヘッダーを設定する方法

はじめに

HTTPセキュリティヘッダーは、ブラウザに対してセキュリティポリシーを伝えるレスポンスヘッダーです。クリックジャッキング・MIME スニッフィング・情報漏洩・XSSなど多くの攻撃を防ぐことができます。WordPress では.htaccess・Nginx設定・functions.phpのいずれかで設定します。

症状・原因

  • セキュリティスキャン(SecurityHeaders.com等)でスコアがF・Dになっている
  • 「X-Frame-Options ヘッダーが見つかりません」と指摘された
  • CSP・HSTS が設定されておらず、現代的なセキュリティ対策が不足している
  • ブラウザのコンソールにセキュリティ警告が表示されている

解決手順

ステップ1:現在のセキュリティヘッダーを確認する

# curl でレスポンスヘッダーを確認
curl -sI https://example.com/ | grep -iE "x-frame|x-content|strict-transport|referrer|permissions|content-security"

# securityheaders.com でオンライン診断(コマンドライン)
curl -s "https://securityheaders.com/?q=example.com&followRedirects=on" | grep -oP "(?<=grade-badge\">)[A-F+]"

# 詳細なヘッダー一覧
curl -sI https://example.com/ | grep -v "^[[:space:]]"

ステップ2:Apacheで設定する(.htaccess)

# WordPress ルートの .htaccess(# BEGIN WordPress の前に追記)
<IfModule mod_headers.c>
    # ① クリックジャッキング対策
    Header always set X-Frame-Options "SAMEORIGIN"

    # ② MIMEスニッフィング対策
    Header always set X-Content-Type-Options "nosniff"

    # ③ XSS フィルター(旧ブラウザ向け)
    Header always set X-XSS-Protection "1; mode=block"

    # ④ リファラー情報の制御
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # ⑤ HTTPS 強制(HSTS)- 1年間
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

    # ⑥ 機能・APIのアクセス制限
    Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"

    # ⑦ サーバー情報の秘匿
    Header unset X-Powered-By
    Header always unset X-Powered-By
    ServerTokens Prod
</IfModule>

ステップ3:Nginxで設定する

# /etc/nginx/sites-available/example.com
server {
    # ... 既存の設定 ...

    # セキュリティヘッダーを一括設定
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

    # サーバー情報を隠す
    server_tokens off;
    more_clear_headers "X-Powered-By";
}

ステップ4:functions.phpで設定する(サーバー設定が変更できない場合)

// functions.php: PHP からセキュリティヘッダーを送信

add_action('send_headers', function(): void {
    // 管理画面では一部ヘッダーを緩和
    $is_admin = is_admin();

    // ① クリックジャッキング対策
    // 管理画面は同一オリジンのiFrameを許可
    header('X-Frame-Options: SAMEORIGIN');

    // ② MIMEスニッフィング対策
    header('X-Content-Type-Options: nosniff');

    // ③ XSS フィルター
    header('X-XSS-Protection: 1; mode=block');

    // ④ リファラー情報
    header('Referrer-Policy: strict-origin-when-cross-origin');

    // ⑤ HTTPS 強制(SSL環境のみ)
    if (is_ssl()) {
        header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
    }

    // ⑥ 機能制限
    header('Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()');

    // ⑦ 不要なヘッダーを削除
    header_remove('X-Powered-By');
    header_remove('Server');
});

// WordPress が出力する X-Pingback ヘッダーを削除
add_filter('wp_headers', function(array $headers): array {
    unset($headers['X-Pingback']);
    return $headers;
});

ステップ5:設定後の確認とスコアチェック

# 設定したヘッダーが送信されているか確認
curl -sI https://example.com/ | grep -iE "x-frame|x-content|strict|referrer|permissions|x-xss"

# 期待される出力:
# x-frame-options: SAMEORIGIN
# x-content-type-options: nosniff
# strict-transport-security: max-age=31536000; includeSubDomains
# referrer-policy: strict-origin-when-cross-origin
# permissions-policy: camera=(), microphone=(), geolocation=()

# WP-CLI でサイトのヘッダーを確認
wp eval "
\$response = wp_remote_head('https://example.com/');
\$headers = wp_remote_retrieve_headers(\$response);
foreach (\$headers->getAll() as \$key => \$value) {
    echo \$key . ': ' . (is_array(\$value) ? implode(', ', \$value) : \$value) . PHP_EOL;
}
"

注意事項

  • Strict-Transport-Security(HSTS)は一度送信するとブラウザが期間中HTTP→HTTPSリダイレクトを強制します。SSL証明書に問題が発生した場合アクセス不能になるため、まずmax-age=300(5分)でテストしてから徐々に延長してください
  • X-Frame-Options: DENYに設定するとWordPress管理画面のカスタマイザーやGutenbergの一部機能が動作しなくなる場合があります。SAMEORIGINを使用してください
  • Permissions-Policyはサイトが実際に使用する機能を誤って制限しないよう注意してください。例えばGoogle Mapsを埋め込んでいる場合はgeolocation=(self)が必要です

まとめ

セキュリティヘッダーの設定は①curl -sI example.comでヘッダーを確認、②Apacheは.htaccess内に7つのヘッダーを追記、③Nginxはadd_headerディレクティブで設定、④functions.phpsend_headersアクションで設定もできる、⑤curl -sIX-Frame-OptionsStrict-Transport-Security等が返ることを確認します。

お気軽にご相談ください

お見積りへ お問い合わせへ