• 診断項目 No.16/127
  • セキュリティヘッダー
  • 重大度 重要(high)

クリックジャッキング対策とは?X-Frame-Options と CSP frame-ancestors の違い・設定方法・診断基準

クリックジャッキング対策は、自サイトを他サイトのiframeに埋め込ませないようブラウザに指示するヘッダー設定です。frame-ancestorsとX-Frame-Optionsの違いと優先関係、Apache・nginx・IIS・Next.jsの設定例と診断基準を解説します。

結論(クリックジャッキング対策)

クリックジャッキング対策とは、攻撃者のサイトに自サイトを透明なiframeで重ね、別のボタンに見せかけて操作させる攻撃(クリックジャッキング)を防ぐため、他サイトからの埋め込みをブラウザに禁止させる設定です。現行の標準は Content-Security-Policy の frame-ancestors 'self'(または 'none')で、旧来の X-Frame-Options: SAMEORIGIN(または DENY)を互換のために併用します。どちらもレスポンスヘッダーで送る必要があり、meta要素では効きません。

この記事のポイント

  • frame-ancestors はmeta要素では無視され、default-src にもフォールバックしないため、レスポンスヘッダーで明示します。
  • 強制CSPに frame-ancestors があるとX-Frame-Optionsは無視されるため、frame-ancestors * と DENY の併記は埋め込みを許してしまいます。
  • X-Frame-Optionsの有効値は DENY と SAMEORIGIN だけで、ALLOW-FROM は現行ブラウザで無視されます。
  • JavaScriptによるフレーム破り(frame busting)は sandbox 属性などで回避できるため、対策として不十分です。
  • セキュリティAIチェッカーは有効な frame-ancestors、または(それがなく)X-Frame-Options が DENY/SAMEORIGIN なら○、それ以外は×と判定します。
診断項目名クリックジャッキング対策
項目IDheaders.frame
分類セキュリティヘッダー
重大度・配点の重み重要(high) 重み 3
関連する標準・ガイドラインOWASP ASVS 5.0.0 V3.4.6(L2:全応答でCSP frame-ancestorsを使用。X-Frame-Optionsは廃止扱いで依存不可)、OWASP WSTG-CLNT-09(Testing for Clickjacking)、IPA「安全なウェブサイトの作り方」1.9 クリックジャッキング、CWE-1021(UIレイヤーやフレームの不適切な制限)

クリックジャッキング対策とは

クリックジャッキングとは、攻撃者のサイトの中に標的サイトを透明なiframeで重ね、利用者には別のボタンを見せながら、実際には標的サイトのボタンを押させる攻撃です(UI redressing)。ログイン状態のまま「送信」「削除」「設定変更」を押させたり、意図しない申込みをさせたりできます。

クリックジャッキング対策とは、自サイトのページを他サイトから埋め込ませないようブラウザに指示するレスポンスヘッダーを設定することです。使うヘッダーは次の2つです。

ヘッダー位置付け推奨値
Content-Security-Policy: frame-ancestors現行の標準'self'(または 'none')
X-Frame-Options旧来の方式。互換のため併用SAMEORIGIN(または DENY)
Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN

セキュリティAIチェッカーのこの項目は、トップページの応答に、これらの有効な埋め込み制限があるかを確認します。トップページ以外の全HTMLへの適用は「クリックジャッキング対策を全HTMLへ適用」と「CSP frame-ancestorsを全HTMLへ適用」で別に確認します。

frame-ancestors と X-Frame-Options の仕組みと違い

CSP frame-ancestors

W3C CSP3 の frame-ancestors は、frame/iframe/object/embed でページを埋め込める親(祖先)を指定します。値は 'none'、'self'、ホスト(https://www.pref.example.lg.jp など)、スキームです。祖先が多段の場合は、すべての祖先が条件を満たす必要があります。

重要な性質は次のとおりです。

  • meta要素では無視される(CSP3が「MUST be ignored」と規定)。必ずレスポンスヘッダーで送ります。
  • default-src にフォールバックしない。default-src 'none' でも、埋め込みは誰でも可能です。
  • frame-ancestors * や frame-ancestors https: は、全サイトからの埋め込みを許すため、対策になりません。
  • Report-Only ヘッダー内の frame-ancestors は遮断しません。

X-Frame-Options

HTML Living Standard(§7.7)が処理モデルを定めています。

  • 有効な値は DENY(全面禁止)と SAMEORIGIN(同一オリジンの祖先のみ許可)だけです。
  • ALLOW-FROM は「実装しない」とされ、現行ブラウザは無視します(埋め込み可能の扱い)。
  • 強制CSPに frame-ancestors があると、X-Frame-Options は無視されます。 したがって、frame-ancestors * と X-Frame-Options: DENY を併記すると、埋め込みは許可されてしまいます。
  • ヘッダーが重複して SAMEORIGIN, SAMEORIGIN のように届いた場合、値は小文字化した集合として扱われ、重複は1つにまとまり、SAMEORIGIN として有効です。
  • DENY, SAMEORIGIN のように異なる有効値が混在すると、「混乱した設定」として埋め込みは全面的にブロックされます。無効値だけが複数ある場合は、ヘッダーなしと同じです。
  • meta要素で書いた X-Frame-Options は効果がありません(MDN)。

なぜ frame-ancestors が推奨されるのか

ASVS 5.0.0 V3.4.6 は、全HTTP応答で frame-ancestors を使い、既定で埋め込み不可、必要な資源だけ許可することを求めています。そして X-Frame-Options は「廃止され依存できない」と注記しています。複数の許可オリジンを指定できるのも frame-ancestors だけです。一方で、ごく古いブラウザ対策として、X-Frame-Options の併用は無害です。

JavaScriptによるフレーム破り(frame busting)は不十分

if (top !== self) top.location = self.location; のようなスクリプトは、iframeの sandbox 属性やJavaScriptの無効化で回避できると、WSTG-CLNT-09が説明しています。クリックジャッキング対策は、サーバー側のヘッダーで行います。

クリックジャッキング対策の診断基準(セキュリティAIチェッカー)

取得対象

  • トップページの最終応答のレスポンスヘッダー Content-Security-Policy(強制ポリシー。カンマ区切りの複数ポリシーを個別に評価)と X-Frame-Options を取得します。
  • HTML内のmeta CSPは、ブラウザが frame-ancestors を強制しないため判定に使わず、根拠欄で注意喚起だけを行います。

判定ロジック

  1. 強制CSPヘッダーに frame-ancestors があるかを確認します。
    • ある場合、ブラウザは X-Frame-Options を無視するため、frame-ancestors の値だけで判定します。
    • いずれかのポリシーの frame-ancestors が、全オリジン許可(*、https://* 等)やスキーム全体の許可(https:、http:、wss:、ws:)を含まなければ有効(○)です。
    • すべてが広すぎる場合は×です。
    • 値が空の frame-ancestors は 'none' と同じ扱いです。
  2. frame-ancestors がない場合、X-Frame-Options をカンマで分割・小文字化した集合に deny または sameorigin が含まれれば○です(HTML仕様の処理モデルに準拠)。ALLOW-FROM や不明な値だけなら×です。

判定条件

判定条件得点への影響
○ 問題なし(pass)有効な frame-ancestors、または(frame-ancestorsがなく)X-Frame-Options に DENY/SAMEORIGIN3点
× 要改善(fail)対策ヘッダーなし、frame-ancestors が全許可、X-Frame-Options が ALLOW-FROM・無効値のみ、meta CSPのみ0点
対象外(na)なし(この項目は常に判定します)—

ASVSが求める「全応答への適用」は、「クリックジャッキング対策を全HTMLへ適用」(crawl.frame-coverage、複数ページ)と「CSP frame-ancestorsを全HTMLへ適用」(crawl.csp-frame-ancestors-coverage、frame-ancestorsの有無)で別途評価します。

自治体サイトでの判定例

レスポンスヘッダー判定
X-Frame-Options: SAMEORIGIN○
X-Frame-Options: SAMEORIGIN, SAMEORIGIN(Apacheとアプリで二重付与)○
Content-Security-Policy: frame-ancestors 'self' https://www.pref.example.lg.jp○
Content-Security-Policy: frame-ancestors * + X-Frame-Options: DENY×(XFOは無視される)
X-Frame-Options: ALLOW-FROM https://example.jp×
meta CSP に frame-ancestors 'self' のみ×

frame-ancestors * のようなワイルドカードは、「CSPの過剰なワイルドカード」でも△として検出されます。

クリックジャッキング対策がないとどんなリスクがあるか

  • 意図しない操作:電子申請、施設予約、メール配信の登録・解除、職員向けのCMS管理画面などがiframeで埋め込めると、ログイン中の利用者・職員に、投稿の公開・削除・設定変更・申込みのボタンを押させることができます。
  • 入力の誘導:クリックだけでなく、重ねた透明なフォームへ文字を入力させるなど、操作全般を誘導される可能性があります。
  • なりすまし表示:公式サイトを枠内に表示して偽の案内を重ね、信頼性を悪用する詐欺サイトに使われる可能性があります。

IPA「安全なウェブサイトの作り方」が示す対策

IPAの「安全なウェブサイトの作り方」は、クリックジャッキングへの対策を次のように整理しています。

  • 根本的解決:X-Frame-Options ヘッダーで他ドメインからの埋め込みを制限すること、または処理を実行する直前のページで再度パスワードの入力を求めること
  • 保険的対策:重要な処理を、一連のマウス操作だけで実行できないようにすること

現在は、これに加えて、ASVSが求める frame-ancestors の併用が推奨されます。

クリックジャッキング対策の設定方法(Apache・nginx・IIS・Next.js)

設定の手順

  1. 埋め込みの必要性を確認:自サイトのページを他サイト(県のポータル、観光サイト、庁内ポータル等)にiframeで載せる運用があるかを確認します。
  2. 既定は 'self':自サイト内でのiframe利用だけなら、frame-ancestors 'self' + X-Frame-Options: SAMEORIGIN。iframe利用が一切ないなら、'none' + DENY にします。
  3. 外部に埋め込ませる場合:該当ページのフォルダだけ frame-ancestors 'self' https://許可先 とし、そのフォルダでは X-Frame-Options を外します(SAMEORIGINのままだと古いブラウザで表示されないため)。
  4. 全応答に適用:HTMLだけでなく、エラーページ・PDF表示等にも共通設定で付与します。

Apache(.htaccess)

<IfModule mod_headers.c>
  Header always set X-Frame-Options "SAMEORIGIN"
  # 既存のCSPがある場合は、そのCSPの値に frame-ancestors を追記する(別のCSPヘッダーを足すと両方が適用される)
  Header always set Content-Security-Policy "frame-ancestors 'self'"
</IfModule>

外部サイトへの埋め込みを許すフォルダの .htaccess:

<IfModule mod_headers.c>
  Header always unset X-Frame-Options
  Header always set Content-Security-Policy "frame-ancestors 'self' https://www.pref.example.lg.jp"
</IfModule>

Header set と Header always set は別の表に格納されるため、上書き・削除するときは同じ種類(always)で指定してください。二重付与で SAMEORIGIN, SAMEORIGIN となっても動作上は有効ですが、設定箇所を1つに整理するのが望ましいです。

nginx

add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;

IIS(web.config)

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="X-Frame-Options" value="SAMEORIGIN" />
      <add name="Content-Security-Policy" value="frame-ancestors 'self'" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Next.js(Vercel)

// next.config.js
module.exports = {
  async headers() {
    return [{
      source: '/(.*)',
      headers: [
        { key: 'X-Frame-Options', value: 'DENY' },
        { key: 'Content-Security-Policy', value: "frame-ancestors 'none'" },
      ],
    }];
  },
};

既に別のCSPを設定している場合は、その値に frame-ancestors を含めて1本にまとめます。

CMS(WordPress)を利用している場合

WordPressは、管理画面とログイン画面に X-Frame-Options: SAMEORIGIN を送出しますが、公開ページには付けません。サーバー設定でサイト全体に付与してください。CMSのプレビュー機能が管理画面内のiframeで公開ページを表示する場合も、'self' であれば動作します。

設定後の確認方法

curl -sI https://www.example.lg.jp/ | grep -iE '^(x-frame-options|content-security-policy):'

あわせて、別ドメインに置いたテスト用HTML(<iframe src="https://www.example.lg.jp/"></iframe>)を開き、表示が拒否され、コンソールに frame-ancestors または X-Frame-Options による拒否が出ることを確認します。

よくある質問(FAQ)

クリックジャッキング対策には X-Frame-Options と frame-ancestors のどちらを使えばよいですか?

現行の標準は CSP の frame-ancestors で、ASVS 5.0.0 は X-Frame-Options を「廃止され依存できない」と注記しています。ごく古いブラウザ対策として X-Frame-Options の併用は無害なので、両方を設定するのが一般的です。

X-Frame-Options の ALLOW-FROM は使えますか?

使えません。HTML Living Standard は ALLOW-FROM を「実装しない」としており、現行ブラウザは無視して埋め込み可能の扱いになります。特定のサイトに埋め込みを許すには frame-ancestors に許可先のオリジンを書きます。

metaタグで frame-ancestors や X-Frame-Options を書けば対策になりますか?

なりません。CSP3は meta 要素の frame-ancestors を無視すると規定しており、meta 要素の X-Frame-Options も効果がありません。必ずレスポンスヘッダーで送ります。

X-Frame-Options が SAMEORIGIN, SAMEORIGIN と二重に付いていますが問題ですか?

動作上は有効です。HTML仕様の処理モデルでは値を小文字化した集合として扱うため、重複は1つにまとまり SAMEORIGIN として働きます。ただし設定箇所は1つに整理するのが望ましいです。DENY, SAMEORIGIN のように異なる有効値が混在すると埋め込みは全面的にブロックされます。

県のポータルサイトなど他サイトに自サイトをiframeで載せたい場合はどうすればよいですか?

該当ページのフォルダだけ frame-ancestors 'self' https://許可先 とし、そのフォルダでは X-Frame-Options を外します。SAMEORIGIN のままだと古いブラウザで表示されないためです。

JavaScriptで top !== self を判定するフレーム破りでは不十分ですか?

不十分です。WSTG-CLNT-09 が説明しているとおり、iframe の sandbox 属性や JavaScript の無効化で回避できます。サーバー側のレスポンスヘッダーで対策してください。

WordPressはクリックジャッキング対策をしてくれますか?

WordPressは管理画面とログイン画面に X-Frame-Options: SAMEORIGIN を送出しますが、公開ページには付けません。サーバー設定でサイト全体に付与してください。

セキュリティAIチェッカーを利用する

この項目を含む127項目を、URLを入れるだけで無料診断します。

参考資料