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.phpとwp-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.phpのsend_headersフックでheader('X-Frame-Options: SAMEORIGIN')を送信、⑤現代的なContent-Security-Policy: frame-ancestors 'self'と併用します。