画面をだましてクリックさせる攻撃
クリックジャッキングとは?『プレゼントを受け取る』ボタンの裏に隠れた罠を図解
画面には「無料クーポンを受け取る」と書かれているのに、実際に押されるのはまったく別のサービスのボタン。そんなことがブラウザの仕組みを悪用して起こり得ます。
1. 押したのは本当にそのボタン?
たとえば、SNSにログインしたまま、友達が紹介した「動画プレゼント」のページを開いたとします。真ん中に「動画を再生する」という大きなボタンがあり、あなたは自然にクリックします。
ところが、ボタンの位置には、別のサイトの「アカウントをフォローする」ボタンが透明な状態で重ねられていたとしたらどうでしょう。あなたには再生ボタンしか見えませんが、クリックが届くのは上に乗せられた透明なボタンです。
身近な例では、SNSでのフォロー、カメラや通知の許可、アカウント設定の変更など、クリックで確定する操作が狙われ得ます。ただし、実際に成功するかどうかは、対象サイトの埋め込み制限や操作時の確認によって変わります。
2. 透明なページを重ねる仕組み
鍵になるのはiframeです。iframeは、あるWebページの中に別のページを小窓として表示するためのHTML要素。地図や動画の埋め込みでも使われる、普通の機能です。
下の層:攻撃者が見せたい画面
上の層:ほとんど透明なiframe(利用者には見えにくい)
通常は最前面の要素がクリックを受け取ります。攻撃者はiframeの透明度・位置・サイズを調整し、利用者が押したいボタンの上に、本当の操作ボタンをぴったり重ねようとします。iframeが透明でも、その中の操作部品がクリックを受け取れる状態であれば問題になります。
一方で、iframeの中にある別サイトのDOMを、攻撃者のページから自由に読み書きできるわけではありません。通常は同一オリジンポリシーがそれを制限します。クリックジャッキングは、その読み取り制限を突破せずに「人間のクリック」を悪用する点が特徴です。
3. 被害が起こるまでを追いかける
利用者
SNSにはログイン済み
攻撃者のページ
クーポンや動画を装う
正規サイト
本物の操作ボタンがある
- 利用者がSNSなど、正規サービスにログインした状態になる。
- 攻撃者が用意したキャンペーン風のページを開く。
- そのページには、正規サービスのページを表示する透明なiframeが置かれている。
- 正規サービスが外部からのiframe埋め込みを許していると、隠れたページが表示可能になる。
- 利用者が見えている「再生」ボタンをクリックしたつもりで、正規サービス側の操作ボタンを押す。
- 追加の確認なしで完了する処理なら、本人の意図に反した状態変更が起こる可能性がある。
4. ブラウザに「埋め込み禁止」を伝える
最も直接的な対策は、正規サイト側が「他のサイトのiframeに自分のページを表示させない」よう指示することです。HTTPレスポンスヘッダーで設定します。
CSPのframe-ancestors
Content-Security-Policy: frame-ancestors 'none';これを返したページは、他のページのiframeなどの内側に表示することを禁止します。「自分のサイト内での埋め込みだけ許す」場合は frame-ancestors 'self' を使います。許可する外部サイトが本当に必要な場合は、そのオリジンを限定します。
X-Frame-Options
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN # 代替設定の例。両方を同時に送らないDENY は埋め込み禁止、SAMEORIGIN は同一オリジンによる埋め込みだけを許します。現代的な柔軟な制御にはCSPのframe-ancestorsが適しています。
frame-ancestors はHTML内の <meta> では設定できません。必ずHTTPレスポンスヘッダーで送ります。また、default-src で自動的に代用されるものではありません。5. Cookieと追加確認はどう役立つ?
ログインが必要な操作なら、ブラウザが埋め込まれたサイトにログインCookieを渡さなければ、操作は成立しにくくなります。SameSite=Lax/Strict は、典型的なクロスサイトiframeへのCookie送信を抑えます。
ただしSameSiteだけでは不十分です。ログイン不要の操作には効きません。同じサイトに属する別サブドメインからの埋め込みなど、Cookieが送られる場合もあります。埋め込みそのものを防ぐframe-ancestorsを中心にしてください。
送金・退会・外部連携の許可などでは、内容を再表示し、再認証や取引内容に結び付いたサーバ側の確認を求めるのも有効です。単に「OK」ボタンをもう一つ増やすだけでは、同様の見せかけ操作に利用され得ます。
以前はページ内のJavaScriptでiframeから抜け出す「frame-busting」も使われましたが、これだけに頼るのは危険です。ブラウザに埋め込み制限を伝えるヘッダーを優先します。
6. 手を動かして確かめる
動画・クーポン・抽選の3場面から選んで、埋め込み制限、Cookie、追加確認の設定を切り替えてみましょう。「見えているボタンを押したとき、裏側では何が起きるのか」を比べられます。
体験:そのクリック、本当に見えているボタン?
ここは説明用の安全な模型です。実際の外部サイトやログイン操作は呼び出しません。
見えているページ:キャンペーンサイト
今日だけの特別企画!
実サイトのクリックを発生させない模型です。
裏で狙われている操作
公開プロフィールに変更
見えているのはクーポン、下にあるのは設定変更ボタン
埋め込み:許可される / Cookie:届く想定
注意:実ブラウザはCookieのSecure属性、第三者Cookie制限、サイト境界、iframeの階層なども考慮します。このラボは典型的なクロスサイトiframeの判定を単純化しています。
7. CSRF・XSSとの違い
| 攻撃 | だます対象 | 典型的な対策 |
|---|---|---|
| クリックジャッキング | 人の目とクリック位置 | frame-ancestors、重要操作の追加確認 |
| CSRF | ログイン中のブラウザが送るリクエスト | CSRFトークン、Origin検証、SameSite |
| XSS | ブラウザのHTML/JavaScript解釈 | 出力エスケープ、安全なDOM操作、サニタイズ |
クリックジャッキングは、通常、別サイトに正規ページを埋め込んで見た目を操作します。CSRFは偽のリクエストを送らせる攻撃、XSSはWebページ内で文字列を命令として動かす問題です。組み合わせて悪用されることもあります。
8. Web開発者向け:具体的な設定
アカウント設定・決済・管理画面のような、第三者のサイトから埋め込む必要がない画面には、まず埋め込み禁止のヘッダーを設定します。Next.jsでは、たとえば次のように指定できます。
// next.config.ts(例)
const nextConfig = {
async headers() {
return [{
source: '/account/:path*',
headers: [
{ key: 'Content-Security-Policy', value: "frame-ancestors 'none'" },
{ key: 'X-Frame-Options', value: 'DENY' },
],
}];
},
};
export default nextConfig;既存のCSPがある場合は、別ヘッダーを不用意に上書きしないよう統合してください。CDNやリバースプロキシを使うなら、最終的なHTTPレスポンスに設定が残っているかも確認します。
curl -I https://example.com/account/settingsさらに、ブラウザで実際に第三者のテスト用ページからiframeへ読み込もうとして、ブロックされるか確かめます。埋め込みを許す例外があるページは、許可するオリジンを最小限にします。
9. よくある疑問とまとめ
Q. iframeは全部危険なの?
いいえ。動画や地図の埋め込みなど、正当な利用は多くあります。問題は「重要な操作を行えるページ」が、信頼できない第三者に自由に埋め込まれることです。
Q. HTTPSにしていれば防げる?
HTTPSは通信の暗号化と接続先の認証に役立ちますが、ボタンの重ね合わせを直接は防ぎません。別の対策が必要です。
Q. ユーザー側で気をつけることは?
不審なキャンペーンや誘導リンクへの警戒は役立ちますが、見た目で見破るのは難しい攻撃です。サイト運営者が仕組みとして防ぐことが最も重要です。