X-Frame-Options は「フレームに入れていいかどうか」を決めるスイッチ
まず、X-Frame-Options を一言でいうと、
「このページを、他のサイトの <iframe> や <frame> の中に表示していいかどうか」
をブラウザに伝えるための設定です。
ブラウザはレスポンスヘッダに
X-Frame-Options: DENYX-Frame-Options: SAMEORIGIN
のような値が付いていると、
「このページはフレームに入れてはいけない(あるいは、同一オリジンだけ許可)」
というルールに従って、表示をブロックします。
WordPress でこれを設定する目的は、主に「クリックジャッキング攻撃」を防ぐことです。
クリックジャッキング攻撃をイメージしてみる
見えているボタンと、実際に押しているボタンが違う世界
クリックジャッキングは、ざっくり言うと、
ユーザーには「普通のボタン」を見せておきながら
実際には、その裏に別サイトの重要なボタンを重ねておいて
ユーザーのクリックを“乗っ取る”攻撃
です。
例えば、攻撃者がこんなページを作ったとします。
見た目は「ゲームのスタートボタン」や「プレゼント応募ボタン」
でも、その透明なレイヤーの下に
あなたの WordPress の管理画面(/wp-admin)を iframe で読み込んで
「削除」「設定変更」「ログアウト」などのボタンが、ちょうど同じ位置にある
ユーザーは、
「ゲームのスタートを押したつもり」
「応募ボタンを押したつもり」
なのに、実際には
「WordPress の重要なボタンを押してしまっている」
という状況になります。
これがクリックジャッキングです。
なぜ iframe が鍵になるのか
この攻撃のポイントは、
攻撃者のサイトの中に
あなたのサイトのページを iframe で埋め込めてしまう
という点です。
もしブラウザが、
「このページは、他のサイトの iframe の中に表示してはいけない」
と知っていれば、
そもそもこの攻撃は成立しません。
そこで登場するのが、X-Frame-Options です。
X-Frame-Options がやっていること
ブラウザに「フレーム内表示の可否」を宣言する
レスポンスヘッダに X-Frame-Options を付けると、ブラウザはこう解釈します。
X-Frame-Options: DENY
→ どんなサイトからも、このページを iframe に入れてはダメ
X-Frame-Options: SAMEORIGIN
→ 同じオリジン(同じドメイン・プロトコル・ポート)のページからの iframe だけ許可
→ 他のサイトからの iframe 埋め込みはブロック
クリックジャッキングを防ぎたい場合、
多くのサイトでは
「少なくとも、他のドメインからの iframe 埋め込みは全部禁止したい」
ので、SAMEORIGIN か DENY を使うことが多いです。
ブロックされたときの挙動
攻撃者のサイトが、あなたのページを iframe で読み込もうとするとします。
あなたのページのレスポンスヘッダに
X-Frame-Options: SAMEORIGIN
が付いていると、ブラウザは
「このページは、同じオリジンからしか iframe に入れちゃダメって言ってるな。
今読み込もうとしているのは別ドメインだから、表示をブロックしよう」
と判断します。
結果として、攻撃者のページの中では、
iframe が真っ白になる
エラー表示になる
などして、クリックジャッキングが成立しなくなります。
WordPress で守りたいのはどのページか
特に守りたいのは管理画面と重要な操作画面
クリックジャッキングの観点で、特に守りたいのは
ログイン画面(/wp-login.php)
管理画面(/wp-admin/ 以下)
重要な操作を行う画面(投稿削除、設定変更、ユーザー管理など)
です。
これらが他サイトの iframe に勝手に埋め込まれ、
ユーザーのクリックを乗っ取られると、
意図しない設定変更
投稿の削除
ユーザーの追加・権限変更
など、かなり致命的な被害につながります。
X-Frame-Options を適切に設定すると、
「そもそも、他サイトの中に管理画面を埋め込めない」
状態になるので、
クリックジャッキングのリスクを大きく下げられます。
フロント側も基本は「埋め込まれなくていい」
「うちのサイトは、他のサイトから iframe で埋め込まれる必要があるのか?」
と考えてみてください。
動画プレイヤーや地図サービスのように、
「他サイトに埋め込まれること自体が機能」
というケースは別ですが、
普通のブログや企業サイトであれば、
「わざわざ他ドメインから iframe で表示される必要はない」
ことがほとんどです。
その場合、
サイト全体に対して SAMEORIGIN を設定する
というのは、かなり自然な選択肢になります。
例題:X-Frame-Options が効いている・いない場合の違い
設定なしの場合
あなたのサイト https://example.com の管理画面に、X-Frame-Options が設定されていないとします。
攻撃者は、自分のサイト https://evil.com にこんな HTML を書けます。
<iframe src="https://example.com/wp-admin/" style="opacity:0; position:absolute; top:0; left:0; width:100%; height:100%;"></iframe>
見た目は evil.com のページしか見えませんが、
実際にはその上に透明な example.com/wp-admin/ が重なっている状態です。
ユーザーが evil.com 上の「ゲーム開始」ボタンを押したつもりでも、
実際には wp-admin 内の「削除」ボタンを押しているかもしれません。
X-Frame-Options: SAMEORIGIN を設定した場合
同じ状況で、https://example.com/wp-admin/ のレスポンスヘッダに
X-Frame-Options: SAMEORIGIN
が付いていると、ブラウザは
「これは example.com のページ。
今は evil.com から iframe で読み込もうとしている。
SAMEORIGIN だから、これは許可されない」
と判断し、iframe 内の表示をブロックします。
結果として、攻撃者のページでは管理画面が表示されず、
クリックジャッキングが成立しません。
プログラミングの感覚で捉える「X-Frame-Options 設定」
これは「この画面は外部から iframe で呼び出し禁止」という宣言
Webアプリを作るとき、
このエンドポイントは外部から叩いていい
このエンドポイントは内部からだけ使う
といった区別をしますよね。
X-Frame-Options は、
「この画面は、外部サイトの“中身”として使ってはいけない」
とブラウザに宣言するための仕組みです。
アプリケーションのロジックではなく、
レスポンスヘッダという「プロトコルレベル」で制御している点がポイントです。
CSRF 対策と並ぶ「クリック系攻撃」の防御
フォームの重要操作に対しては、
CSRFトークンを入れて「他サイトからの勝手な POST」を防ぐのが定番です。
X-Frame-Options は、それと並ぶ
「クリックを乗っ取る系の攻撃」に対する防御
だと考えると分かりやすいです。
CSRF:見えないフォーム送信を防ぐ
X-Frame-Options:見えているようで実は別ページを押させる攻撃を防ぐ
という役割分担です。
まとめ:X-Frame-Options 設定は「他サイトの中に勝手に埋め込ませないための盾」
「X-Frame-Options 設定」というテーマの本質は、
自分のサイトのページが
他のドメインの iframe の中に勝手に表示されないようにし
クリックジャッキングのような“クリック乗っ取り攻撃”を防ぐ
ということです。
押さえておきたいポイントは、
クリックジャッキングは「見えているボタンと実際のボタンをずらす」攻撃
X-Frame-Options は「そもそも他ドメインから iframe 埋め込みさせない」ための宣言
特に管理画面や重要操作画面は、SAMEORIGIN か DENY で守る価値が高い
という三つです。
一度、ブラウザの開発者ツールでレスポンスヘッダを見て、
あなたの WordPress が今、X-Frame-Options を返しているかどうかを確認してみてください。
もし何も設定されていないなら、それは「クリックジャッキングに対して丸腰」のサインです。
そこに一枚、プロトコルレベルの“盾”を足してあげる——それが、この設定の意味です。


