「無料クーポンかと思ったら、意図せずSNSをフォローしていた」「面白い記事を読もうとしただけなのに、気づいたら商品を購入していた」――そんな不思議な経験はありませんか?
その裏には、あなたのクリックを乗っ取り、意図しない操作をさせるクリックジャッキング(Clickjacking)という巧妙なサイバー攻撃が隠れているかもしれません。
この記事では、ユーザーを騙す「見えない罠」の仕組みから、具体的な被害事例、そして自分を守るための防御策まで、デモを交えながら徹底解説します。
クリックジャッキングの正体と仕組み
UI Redress攻撃とも呼ばれる「クリックの乗っ取り」
クリックジャッキングは、その名の通り「クリックを乗っ取る(Jack)」攻撃です。攻撃者が用意した偽のWebページ上に、透明化した別のサイトを重ねることで、ユーザーの操作をだまし取ります。
この手口は、Webサイトの見た目(UI)を偽装(Redress)することから、UI Redress攻撃 とも呼ばれます。
攻撃者は何を狙っているのか?
攻撃者が狙うのは、ユーザーがログイン状態で行う重要な操作です。例えば、以下のようなアクションが標的になります。
金銭的な被害: ネットショッピングでの意図しない商品購入や、有料サービスへの登録
SNSアカウントの操作: 勝手に「いいね!」や「フォロー」、投稿をさせられる
アカウント設定の変更: 気づかぬうちにパスワード変更や退会手続きをさせられる
権限の許可: アプリ連携(OAuth)の承認や、PCのカメラ・マイクへのアクセス許可
クリックジャッキングは、こうして行われる
クリックジャッキングは、Webページの基本的な技術である <iframe> と CSS を悪用して実現されます。その手口を2つの層に分けて見てみましょう。
- 裏のページ(おとり) ユーザーの興味を引く「景品が当たる!」「限定動画を再生」といった、無害に見えるボタンやリンクが配置されています。
- 表のページ(ターゲット)
<iframe>タグで読み込まれた、あなたのSNSやショッピングサイトなど。CSSのopacityプロパティで完全に透明化されています。
攻撃者は、この2つのページをピタリと重ね合わせます。あなたが「動画を再生」ボタンをクリックしたつもりが、その真下には透明な「商品購入」ボタンが隠れている、という仕組みです。
クリックジャックの実践!デモンストレーション
以下の2つのHTMLファイルを同じフォルダに保存し、clickjacking.htmlをブラウザで開いてみてください。
見た目は「見かけ上のボタン」が表示されています。しかしそのボタンをクリックすると、実際には透明にして隠した「本物のボタン」がクリックされます。
clickjacking.html(悪意がある攻撃者のページ)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Clickjacking PoC</title>
<style>
/* iframeを見かけ上のボタンの上にピッタリ重ねる */
.frame-wrapper {
position: relative;
display: inline-block;
}
.fake-button {
position: relative;
z-index: 1;
}
iframe {
position: absolute;
top: 0;
left: 0;
width: 200px; /* 本物ボタンのサイズに合わせる */
height: 40px;
opacity: 0.40; /* 透明にする */
z-index: 2;
border: none;
}
</style>
</head>
<body>
<h1>Clickjacking</h1>
<p>このボタンを押してみてください:</p>
<div class="frame-wrapper">
<button class="fake-button">見かけ上のボタン</button>
<iframe src="target.html"></iframe>
</div>
</body>
</html>
攻撃者側のスタイルシートについて補足します。
position: absolute: iframeを偽ボタンと完全に重ねるopacity: 0.4: iframeを透明にして存在を隠す(ここでは解説の為に半透明にしていますが、実際の攻撃では透明の0にします)z-index: 2: iframeを偽ボタンより前面に配置して、クリックを横取りする
target.html(攻撃対象のページ。我々が守るべきページ)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Target</title>
</head>
<body>
<button onclick="alert('ターゲットボタンがクリックされました!')">
本物のボタン
</button>
</body>
</html>
これは攻撃される側のページです。シンプルなボタンが1つあり、クリックすると「ターゲットボタンがクリックされました!」というアラートが表示されます。


何が起きているのか
- ユーザーには「見かけ上のボタン」という無害そうなボタンが見える
- しかし実際には、その上に
target.htmlを読み込んだiframeが透明で重ねられている - ユーザーが見かけ上のボタンをクリックすると、実際にはiframe内の「本物のボタン」をクリックしている
- 結果として、ユーザーの意図しない操作が実行される
デモ用htmlのボタン押下でalertの反応がない場合
上記の2つのhtmlファイルを同じフォルダに格納して、攻撃者側のhtmlをブラウザで開き、ボタンを押下しても、ターゲット側のalertが反応しない場合があります。file:// スキームで開いている場合、iframe の挙動が制限される為と思われます。その場合は、次の手順で実行すると良いでしょう。
- コマンドプロンプトでカレントディレクトリを2つのhtmlファイルのパスにする
python -m http.server 8000
でポート8000番でサーバー起動する。
※python -mは、Pythonをモジュールとして実行するためのオプションです。
※http.serverはPythonの標準ライブラリとして組み込まれています。- ブラウザで次のURLを開く
http://localhost:8000/clickjacking.html - ブラウザの「見かけ上のボタン」をクリック
→ iframe 内の target.html のボタンが押されて alert() が出るはずです。
実際にあったクリックジャッキングの怖い話
クリックジャッキングは、理論上の脅威ではありません。過去に何度も、私たちの身近なサービスで実際に被害が発生しています。
- 事例1:SNSでの意図しない「いいね!」やシェアの拡散 最も有名なのが、2010年頃にFacebookやTwitterで多発した事例です。「無料ギフト券が当たる!」といった魅力的なボタンをクリックしたユーザーが、気づかないうちに特定のページに「いいね!」を押し、その情報が友達のフィードにまで拡散されてしまうというもの。攻撃者はこれを利用して、悪意のあるサイトへの誘導や、アフィリエイト収入を得ていました。
- 事例2:不正なアプリ連携(OAuth)の承認 「このアプリと連携すると便利になります」という偽のポップアップを表示し、その裏に本物のGoogleやFacebookの「連携許可」ボタンを透明に重ねます。ユーザーが「閉じる」ボタンなどをクリックしたつもりが、実際には意図しないアプリに個人情報へのアクセス権(連絡先、投稿内容など)を与えてしまうのです。
- 事例3:ブラウザ権限の乗っ取り さらに悪質なケースでは、Web会議ツールなどを装い、PCのカメラやマイクへのアクセス許可を求める画面を悪用します。ユーザーが偽の「会議に参加」ボタンをクリックすると、裏で本物の「許可」ボタンが押され、盗撮や盗聴につながる危険性がありました。
対応策:クリックジャッキングからWebサイトを守る
Webサイトをこの巧妙な攻撃から守るためには、サーバー側での適切な設定が不可欠です。主な対策はHTTPレスポンスヘッダーに特定の情報を追加すること。ここでは、現在主流の2つの方法を詳しく解説します。
対策1:X-Frame-Options
X-Frame-Options は、他のサイトがあなたのWebページを <iframe> や <frame>、<object> タグで埋め込むことをブラウザに制御させるための、古くからある信頼性の高いヘッダーです。いわば「うちのページは、他人のサイト内では表示させません」という意思表示です。
設定できる値は3種類あります。
DENY最も強力な設定です。どのサイトからの埋め込みも、一切許可しません。自サイト内のページからの埋め込みも拒否します。HTTPX-Frame-Options: DENYSAMEORIGIN一般的に推奨される設定です。同一オリジン(同じドメイン、プロトコル、ポート)からの埋め込みのみを許可します。例えば、example.comのページは、同じexample.comの別のページ内でのみ<iframe>で表示できます。HTTPX-Frame-Options: SAMEORIGINALLOW-FROM uri特定のURIからの埋め込みのみを許可します。ただし、このディレクティブは一部のブラウザでサポートされていないため、現在では利用は推奨されません。
対策2:Content Security Policy (CSP) の frame-ancestors
Content Security Policy (CSP) は、XSS(クロスサイトスクリプティング)など、さまざまな攻撃を防ぐための非常に強力で柔軟な仕組みです。その中にある frame-ancestors ディレクティブが、クリックジャッキング対策の現代的な標準とされています。
X-Frame-Options よりも、きめ細やかな設定が可能です。
- 一切の埋め込みを拒否する場合 (
DENYと同等)HTTPContent-Security-Policy: frame-ancestors 'none'; - 同一オリジンからのみ許可する場合 (
SAMEORIGINと同等)HTTPContent-Security-Policy: frame-ancestors 'self'; - 複数の特定のドメインを許可する場合
X-Frame-Optionsではできなかった、複数のドメインからの埋め込みを安全に許可できます。パートナーサイトなど、信頼できる特定のサイトがある場合に非常に有効です。HTTPContent-Security-Policy: frame-ancestors 'self' https://partner-site.com https://another-trusted.jp;
💡 どちらを使えばいい? 現在では、CSPの frame-ancestors を利用するのがベストプラクティスです。ただし、古いブラウザとの互換性を最大限に確保したい場合は、X-Frame-Options: SAMEORIGIN も併せて設定しておくと、より堅牢になります。
(非推奨)フレームバスティングについて
以前は、JavaScriptを使ってページが <iframe> 内に埋め込まれていたら、強制的にトップページに遷移させる「フレームバスティング」という手法がありました。しかし、この方法は攻撃者によって容易に回避されてしまうため、現在では信頼性の低い対策とされています。
まとめ:あなたのサイトは大丈夫?最終チェックリスト
クリックジャッキングはシンプルな仕組みですが、ユーザーに大きな被害をもたらす可能性があります。最後に、あなたのサイトが安全かを確認するためのチェックリストです。
- HTTPレスポンスヘッダーを確認したか? すべてのページで、
Content-Security-Policy: frame-ancestors 'self';またはX-Frame-Options: SAMEORIGIN(もしくはDENY)が設定されていることを確認しましょう。 - 重要な操作ページの設定は万全か? 特に、アカウント情報の変更、購入処理、退会ページなど、ユーザーの重要なアクションを伴うページでは、
frame-ancestors 'none'やX-Frame-Options: DENYといった最も厳しい設定を適用することを検討してください。 - 設定を定期的に見直しているか? セキュリティは「一度設定したら終わり」ではありません。新しい技術や脅威が登場する中で、サイトのセキュリティ設定が今も最適であるか、定期的に棚卸しする習慣が大切です。
正しい防御策を導入し、ユーザーが安心して使えるWebサイトを維持しましょう。


