【入門編】 Clickjacking (クリックジャッキング) とFrame Busting – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!新米IT担当者や、これからWebセキュリティを学び始める開発者の皆さん、日々の開発やインフラ管理お疲れ様です。

セキュリティの勉強を始めると、専門用語や横文字が次々に出てきて頭がパンクしそうになりますよね。「クロスサイト・スクリプティング?」「SQLインジェクション?」……何だか難しそうだなと感じるのも無理はありません。

でも、安心してください。セキュリティの基本は、私たちが普段暮らしている「現実世界の防犯」と全く同じなんです。

今回は、Webブラウザの仕組みの隙を突く少しユニークな攻撃「クリックジャッキング」と、それをスマートに防ぐ「フレームバスティング(Frame Busting)」や最新の防御ヘッダーについて、身近な例えを交えながら優しく紐解いていきたいと思います。一歩ずつ、一緒に学んでいきましょう!

—

1. クリックジャッキングってどんな攻撃?(現実世界で例えてみよう)

まずは、攻撃者が何をしようとしているのかをイメージしてみましょう。

想像してみてください。あなたは今、街で見かけた「豪華な海外旅行が当たる!『ここをクリックして応募』というキャンペーンサイト」にアクセスしています。画面の真ん中には、キラキラした魅力的なボタンが表示されています。あなたは疑うことなく、そのボタンを「ポチッ」とクリックしました。

……しかし、実はその裏で、悪巧みをしている泥棒がこんな罠を仕掛けていたらどうでしょう?

あなたのクリックした「ボタンのすぐ真下」には、完全に透明で見えないシート(ガラス)が重ねられていて、その透明シートの裏側では、あなたの大切な銀行口座の「全額送金ボタン」がぴったりと重なっていたのです。

あなたが「旅行当たるといいな!」と思って押したクリックは、そのまま透明シートを突き抜けて、裏側にあった「送金ボタン」を押してしまった――これが、クリックジャッキング(Clickjacking)の正体です。UI(ユーザーインターフェース)が乗っ取られてしまうことから、「UI赤外(UI Redress)」とも呼ばれます。

ブラウザの世界で何が起きているのか?

技術的な仕組みも、今の例えと全く同じです。Webサイトには、別のWebサイトを自分のページの中に窓のように埋め込む <iframe> という便利なタグがあります。

攻撃者は、自分が作った悪意あるサイトのなかに、被害者(あなた)が普段使っているSNSやネット銀行のページを <iframe> で読み込ませます。そして、CSS(デザインを整える言語)を使って、その読み込んだページを完全に透明(不透明度をゼロに)にし、ユーザーがクリックしたい偽のボタンの真上に、本物の重要なボタンが重なるように配置するのです。

ユーザーは自分が安全なサイトを操作していると信じ込まされているため、巧妙に仕組まれた罠の上で、知らず知らずのうちに大切な操作(退会ボタン、パスワード変更、送金など)を実行させられてしまいます。

—

2. 昔の対策:JavaScriptによる「フレームバスティング」の限界

「じゃあ、自分のサイトが勝手にほかの怪しいサイトの <iframe> の中に埋め込まれないようにすればいいんだよね?」

その通りです!よく気が付きましたね。最初に考え出された対策が、JavaScriptを使って「もし自分のサイトが誰かの <iframe> の中に入れられたら、勝手に画面をブッ飛ばして(Bust)単独のウィンドウで開き直す」という方法です。これをフレームバスティング(Frame Busting)と呼びます。

例えば、昔よく使われていたコードはこのようなものです。

<!-- フレームバスティングの古いJavaScriptコード例 -->
<script type="text/javascript">
    // もし現在のウィンドウ(top)が、自分自身のウィンドウ(self)と違っていれば
    // (=誰かのiframeの中に埋め込まれている状態だったら)
    if (top !== self) {
        // 親のウィンドウのURLを強制的に自分のURLに書き換えて、閉じ込める
        top.location = self.location;
    }
</script>

一見すると、「おお、賢い防犯システムだ!」と思いますよね。しかし、セキュリティの世界はイタチごっこです。攻撃者たちは、このフレームバスティングを無効化するずる賢いテクニック(onbeforeunloadイベントを使ったループ妨害や、サンドボックス属性の悪用など)をすぐに編み出しました。

そのため、現在では「JavaScriptだけでフレームバスティングを行うのは不十分(破られやすい)」というのが常識になっています。

—

3. 現代の鉄壁の守り:HTTPヘッダーによる防御

JavaScriptが破られてしまうなら、どうすればいいのでしょうか?
答えは、「Webブラウザそのものに、『うちのサイトは絶対に他のサイトの枠(フレーム)の中に表示させないで!』と強い命令を出すこと」です。

これは、頑丈な玄関の鍵を取り付けるようなものです。ブラウザ(警察や警備員のような存在)が、その命令を厳格に守ってくれます。

現在、主に使用されている強力な防御方法は主に2つあります。順番に見ていきましょう。

① X-Frame-Options ヘッダー(伝統的で確実な防犯ロック)

サーバーからWebページを送信する際、HTTPレスポンスヘッダーに X-Frame-Options という設定を付与します。これにより、ブラウザに対して「このページをiframeで読み込んでいいかどうか」を指示できます。

設定できる値は主に以下の2つです。

  • DENY:誰であろうと、絶対に他のサイトの <iframe> でこのページを表示させない(一番強力)。
  • SAMEORIGIN:同じドメイン(運営者が同じサイト)の中であれば、<iframe> での表示を許可する。

実際のWebサーバー(ApacheやNginxなど)の設定例を見てみましょう。実務でもそのまま参考になる設定です。

# 【Apacheのコンフィグ設定例】
# 自社サイトのすべてのページで、他サイトによるiframe内での表示を完全に禁止する
Header always set X-Frame-Options "SAMEORIGIN"
# 【Nginxのコンフィグ設定例】
# 他サイトによるiframe内での表示を完全に禁止する
add_header X-Frame-Options "DENY" always;

② Content Security Policy (CSP) の frame-ancestors(最先端のスマートキー)

X-Frame-Options は非常にシンプルで強力ですが、少し古い規格です。そこで現在、セキュリティの業界標準として強く推奨されているのが、Content Security Policy (CSP) という仕組みの中にある frame-ancestors というディレクティブ(指令)です。

CSPを使うと、「どのサイトからのiframe埋め込みなら許可する」という細かいホワイトリストを構築できます。

# 【HTTPレスポンスヘッダーの例】
# 自分のドメイン(https://example.com)からだけiframeの読み込みを許可する
Content-Security-Policy: frame-ancestors 'self';

もし、まったく許可していない悪意あるサイトがあなたのページを読み込もうとしても、最新のブラウザは「おっと、このサイトはframe-ancestorsでブロックされているぞ」と判断し、中身を表示させずに拒否してくれます。

—

まとめ:安全なWebアプリを作るために

いかがだったでしょうか? クリックジャッキングとフレーム(iframe)を巡る攻防について、イメージをつかんでいただけましたでしょうか。

今日のポイントをもう一度おさらいしておきますね。

1. クリックジャッキングとは、透明な <iframe> を悪用して、ユーザーに気づかれないまま重要なボタンを押させる狡猾な攻撃。
2. 古いJavaScriptによるフレームバスティングは、攻撃者に回避されやすいため信頼しきってはいけない。
3. 現代の基本対策は、HTTPヘッダーである X-Frame-Options や CSP (frame-ancestors) を正しく設定し、ブラウザの力でガッチリ守ること。

新人のうちは、「動くものを作る」だけで精一杯になってしまいがちですが、ユーザーの大切なアカウントや資産を守るためには、こうした「目に見えない裏側のセキュリティ設定」がとても重要になってきます。

難しく考えず、まずは自分が新しく作ったWebページのレスポンスヘッダーに X-Frame-Options: SAMEORIGIN が入っているか、開発者ツールの「ネットワークタブ」を覗く習慣をつけてみてくださいね。一歩ずつ、頼もしいエンジニアへの階段を登っていきましょう!

コメント

タイトルとURLをコピーしました