2026年5月20日

2026年5月20日

WordPressのX-Frame-Optionsを設定してクリックジャッキングを防ぐ方法

はじめに

クリックジャッキング攻撃は、攻撃者がWordPressサイトを透明なiFrameに埋め込み、ユーザーが意図しないボタンをクリックさせる手法です。X-Frame-Optionsヘッダーを設定することで、サイトが不正なiFrameに埋め込まれることを防げます。

症状・原因

  • セキュリティスキャンで「X-Frame-Optionsヘッダーが設定されていません」と指摘された
  • 自分のサイトが悪意のある第三者サイトにiFrameで埋め込まれている
  • 管理画面が外部サイトのiFrameに表示されてしまっている
  • クリックジャッキング脆弱性診断で「中〜高リスク」と評価された

解決手順

ステップ1:現在の設定を確認する

# X-Frame-Options ヘッダーが送信されているか確認
curl -sI https://example.com/ | grep -i "x-frame"

# 管理画面も確認
curl -sI https://example.com/wp-admin/ | grep -i "x-frame"

# WordPress が既に設定しているか確認
# (WordPress 4.2以降は wp-login.php と wp-admin に自動設定される)
curl -sI https://example.com/wp-login.php | grep -i "x-frame"

# 外部サイトにiFrameで埋め込まれているか確認
curl -sI https://example.com/ | grep -i "frame\|content-security"

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

# WordPress ルートの .htaccess(# BEGIN WordPress の前に追記)
<IfModule mod_headers.c>
    # ① 全ページ: 同一オリジンのiFrameのみ許可
    Header always set X-Frame-Options "SAMEORIGIN"

    # ② より厳格: iFrameへの埋め込みを完全禁止
    # Header always set X-Frame-Options "DENY"

    # ③ 特定ドメインのみ許可(非推奨・廃止予定)
    # Header always set X-Frame-Options "ALLOW-FROM https://trusted.example.com"
    # → 代わりに CSP の frame-ancestors を使う
</IfModule>
# mod_headers が有効か確認
apache2ctl -M | grep headers
# headers_module (shared) が表示されれば OK

# 設定後に確認
curl -sI https://example.com/ | grep -i "x-frame"
# x-frame-options: SAMEORIGIN が返れば成功

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

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

    # X-Frame-Options を設定
    add_header X-Frame-Options "SAMEORIGIN" always;

    # always をつけることで 4xx/5xx レスポンスにも付与される
    # always がないと 200 系のみに付与
}
# 設定テストと反映
sudo nginx -t && sudo systemctl reload nginx

# 確認
curl -sI https://example.com/ | grep -i "x-frame"

ステップ4:functions.phpで設定する

// functions.php: WordPress から X-Frame-Options を送信

add_action('send_headers', function(): void {
    // ① 通常ページ: 同一オリジンのみ許可
    if (!is_admin()) {
        header('X-Frame-Options: SAMEORIGIN');
    }
});

// WordPress の wp-login.php と wp-admin には
// デフォルトで SAMEORIGIN が設定されるが、
// フロントエンドには設定されないため追加が必要

// ② WordPress デフォルトの X-Frame-Options フィルター
// (wp-admin のみデフォルトで SAMEORIGIN)
add_filter('x_frame_options', function(string $value): string {
    return 'SAMEORIGIN'; // または 'DENY'
});

ステップ5:より現代的な frame-ancestors(CSP)に移行する

// functions.php: X-Frame-Options の後継 - CSP frame-ancestors

add_action('send_headers', function(): void {
    // X-Frame-Options(後方互換性のため残す)
    header('X-Frame-Options: SAMEORIGIN');

    // CSP frame-ancestors(より柔軟・モダン)
    // 複数ドメインを許可する場合は frame-ancestors を使う
    // X-Frame-Options では ALLOW-FROM は1ドメインしか指定できないが
    // frame-ancestors は複数指定可能

    // 同一オリジンのみ
    // header("Content-Security-Policy: frame-ancestors 'self'");

    // 特定ドメインも許可する場合
    // header("Content-Security-Policy: frame-ancestors 'self' https://partner.example.com");

    // 完全禁止
    // header("Content-Security-Policy: frame-ancestors 'none'");
});
# 設定確認: X-Frame-Options と CSP が両方送信されているか
curl -sI https://example.com/ | grep -iE "x-frame|content-security-policy"

# iFrame に埋め込まれないか手動テスト
# 外部HTMLファイルを作成してテスト
echo '<iframe src="https://example.com/" width="800" height="600"></iframe>' > /tmp/test.html
# ブラウザで /tmp/test.html を開いてiFrameがブロックされるか確認

注意事項

  • WordPress はwp-login.phpwp-adminページに対してデフォルトでX-Frame-Options: SAMEORIGINを送信します。フロントエンドには自動設定されないため、.htaccessまたはNginx設定で追加してください
  • X-Frame-Options: ALLOW-FROM https://trusted.comは現代のブラウザでは非推奨・無効になっています。特定ドメインを許可する場合は必ずContent-Security-Policy: frame-ancestors 'self' https://trusted.comを使用してください
  • Google Search Console・Google Analytics のiFrameプレビュー機能や、一部の管理ツールがiFrameを使用する場合があります。SAMEORIGIN(DENY ではなく)を使用することでWordPress管理画面の正常動作を維持できます

まとめ

X-Frame-Optionsの設定は①curl -sI example.com | grep -i x-frameで現状確認、②Apacheは.htaccess内にHeader always set X-Frame-Options "SAMEORIGIN"を追記、③Nginxはadd_header X-Frame-Options "SAMEORIGIN" alwaysを設定、④functions.phpsend_headersフックでheader('X-Frame-Options: SAMEORIGIN')を送信、⑤現代的なContent-Security-Policy: frame-ancestors 'self'と併用します。

お気軽にご相談ください

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