クリックジャッキングとは
クリックジャッキング(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 を重ねてクリックを奪う | 振込、購入、設定変更 |
| Likejacking | SNS の「いいね」ボタンを透明化して重ねる | 意図しないシェア、フォロー |
| Cursorjacking | CSS でカーソル画像を実際の位置からずらす | 表示と実クリック位置の不一致 |
| 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 セキュリティヘッダ詳解も合わせてご覧ください。