ssecutils
Security / Browser-native guide

クリックジャッキング詳解 - 透明iframeとX-Frame-Options/CSPで防ぐ

透明iframeでUIを重ねて意図しないクリックを誘発する攻撃の仕組み、likejacking/cursorjackingなどUIリドレッシング全般、X-Frame-Options と CSP frame-ancestors による防御を解説します。

8Zero tracking reading surface

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

クリックジャッキング(Clickjacking)は、攻撃者のページに被害サイトを透明な iframe で重ね、被害者が「攻撃者のページのボタンを押した」と思っている裏で、本物のサイトのボタンをクリックさせる攻撃です。UIリドレッシング(UI Redressing)と呼ばれる攻撃ファミリーの代表例で、視覚と実際の操作のズレを突くのが本質です。

被害者はログイン中の状態でこの罠に引っかかると、自分の意思で「OK」を押したつもりが、実は SNS の「フォロー」、銀行の「振込承認」、設定画面の「公開範囲を全公開に変更」といった重大操作を踏んでしまいます。

典型的な攻撃シナリオ

攻撃者は evil.example に次のような HTML を仕込みます:

<style>
  iframe {
    position: absolute;
    top: 0; left: 0;
    width: 100%; height: 100%;
    opacity: 0.001;       /* 視覚的にはほぼ透明 */
    z-index: 999;
  }
  .lure {
    position: absolute;
    top: 280px; left: 420px;
    font-size: 32px;
  }
</style>

<button class="lure">🎁 無料ガチャを引く</button>
<iframe src="https://bank.example/transfer?to=attacker&amount=1000000"></iframe>

ボタンと iframe 内の「送金実行」ボタンが画面上で同じ位置に重なるよう座標を調整しておきます。被害者は「無料ガチャ」だと思って透明 iframe をクリックすると、実際には bank.example送金実行ボタンを押していることになります。

被害者は bank.example にログイン中(Cookie 保持)なので、サーバー側からは正規ユーザーの操作にしか見えません。CSRF と似ていますが、CSRF が「リクエストを自動発火」させるのに対し、クリックジャッキングは 「被害者本人にクリックさせる」のが違いです。これにより、CAPTCHA や「本当に実行しますか?」確認ダイアログさえも被害者本人が突破してしまいます。

UIリドレッシング攻撃の亜種

名称仕組み典型的な被害
クリックジャッキング透明iframe を重ねてクリックを奪う振込、購入、設定変更
LikejackingSNS の「いいね」ボタンを透明化して重ねる意図しないシェア、フォロー
CursorjackingCSS でカーソル画像を実際の位置からずらす表示と実クリック位置の不一致
Drag & Drop Jackingドラッグ操作で別ウィンドウへデータ流出フォーム値・トークン盗難
Double-clickjackingダブルクリックの隙にダイアログを差し替えるOAuth 認可の同意奪取(2024年話題)

防御1: CSP frame-ancestors(現代の主役)

Content-Security-Policy ヘッダの frame-ancestors ディレクティブが、現代における正攻法の防御です。サイトを iframe で埋め込めるオリジンを明示的にホワイトリスト化します。

# 自サイトをどこからも iframe 埋め込みさせない(推奨)
Content-Security-Policy: frame-ancestors 'none'

# 同一オリジンのみ許可
Content-Security-Policy: frame-ancestors 'self'

# 特定パートナーサイトを許可
Content-Security-Policy: frame-ancestors 'self' https://partner.example

ブラウザが iframe 描画前にこのヘッダを確認し、許可されていなければ描画自体をブロックします。frame-ancestors は CSP Level 2 から導入され、現代の主要ブラウザでサポートされています。

防御2: X-Frame-Options(古い仕組み・現役)

X-Frame-Options は CSP frame-ancestors より古い仕組みですが、互換性のため今も併用されます。

挙動
DENYどのオリジンからも iframe 埋め込み不可
SAMEORIGIN同一オリジンからのみ iframe 埋め込み可
ALLOW-FROM uri指定 URI から許可(非推奨・サポート不十分)

現代の指針は 「CSP frame-ancestors を主役、X-Frame-Options は古いブラウザ向け保険」です。両方設定しておけば最大互換。両者の値が矛盾した場合、CSP frame-ancestors が優先されます(CSP Level 2 の仕様)。

本サイト secutils.jp でも次の設定で対応しています:

Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY

防御3: フレームバスティング(非推奨)

2010年代以前は、JavaScript で自身が iframe 内かを判定して脱出する フレームバスティング(frame busting)コードがよく使われました:

if (top !== self) {
  top.location = self.location;
}

しかしこの手法は、HTML5 の sandbox 属性で iframe を起動すれば top.location への書き込みを禁止できるため、容易にバイパスされます。現代では frame-ancestors を使うべきで、フレームバスティングだけに頼るのは危険です。

防御4: SameSite Cookie の補完効果

Cookie に SameSite=Lax または Strict を設定すると、クロスサイトの iframe からは Cookie が送られなくなり、結果としてクリックジャッキングの被害を緩和できます。ただし「Cookie が無くてもクリックで実行できる操作」(公開フォーム、認証不要API 等)には効きません。主防御は CSP frame-ancestors、SameSite は補完と考えます。

実装チェックリスト

  • すべてのページに Content-Security-Policy: frame-ancestors 'none' または 'self' を返している
  • 古いブラウザ対策として X-Frame-Options: DENY または SAMEORIGIN も併用している
  • iframe 埋め込みを許可する必要がある場合、許可先オリジンを明示している(* ワイルドカードは使わない)
  • ログイン・支払い・設定変更などの重大操作には、明示的な再認証や CAPTCHA を併用している
  • Cookie に SameSite 属性を設定している
  • サイトを securityheaders.com で定期チェックしている

まとめ

クリックジャッキングは「視覚的な錯誤を突いて、被害者本人にクリックさせる」攻撃で、CAPTCHA や確認ダイアログでさえ防げない厄介な側面があります。防御の本命は CSP frame-ancestors。これ1行で iframe 埋め込み自体をブラウザ層で遮断できます。X-Frame-Options も合わせて返し、古いブラウザにも対応するのが現代のベストプラクティスです。

Cookie 設定の確認には Cookie Parser ツールで SameSite 属性を可視化できます。HTTP セキュリティヘッダ全般については HTTP セキュリティヘッダ詳解も合わせてご覧ください。

Tool companion

この記事と一緒に使えるツール

Related reading

関連記事