LoginSignup
1
2

More than 1 year has passed since last update.

自サイトがiframeで第三者のサイトへ埋め込まれることへの対策(X-Frame-OptionsもCSPも使えない場合)

Last updated at Posted at 2021-11-12

はじめに

自サイトがiframeで第三者のサイトへ埋め込まれることを避ける方法として本来あるべき姿は、 HTTPレスポンスヘッダーに X-Frame-Options: SAMEORIGIN あるいは X-Frame-Options: DENY を追加することです。

しかし、そのサイトがiframeで埋め込んで利用することを前提としていて、かつ埋め込み元のドメインが異なる場合、X-Frame-Options で対応することはできません。 ( X-Frame-Options: ALLOW-FROM というものも存在していたようですが、最近のブラウザでは廃止されていますので利用できません )

代替方法として、CSP(Content-Security-Policy)の frame-ancestors で指定する方法はありますので、HTTPレスポンスヘッダーの追加が可能であれば、その方法で対応する方法はありますが、HTTPレスポンスヘッダーが追加できなければこの方法で対応することはできません(metaタグでのCSPの設定も行えますが、frame-ancestorsはmetaタグでの設定に対応していません)。

以上のような、条件のあまり宜しくない(制限の厳しい)環境における対策について考えてみました。

考えられる対策

このような場合において、iframeが自サイト外で埋め込まれる問題への簡単な対策として、次の方法が挙げられます。

  • ページ読み込み時において、コンテンツをCSSで不可視 ( display:none )とする。(JavaSciptが無効化されている状態においては、コンテンツの不可視で対応する)
  • JavaScriptで埋め込み元サイトのドメインをチェックする(parent.location.href で埋め込み元サイトのURLが取得可能)。
  • 埋め込み元サイトのドメインが自サイトに関連する場合は、コンテンツの不可視を解除 ( display:block )とする。
  • 埋め込み元サイトのドメインが自サイトに関連しない場合は、不可視のままとし、かつコンテンツを削除する。

サイトの環境(条件)によっては対応可能な事項は他にもあるかもしれませんが、自サイト(オリジナルサイト)が第三者のサイトにiframeで埋め込まれることを避けることだけを目的とし(それ以外のことは考えず)、かつ閲覧環境は最近のWebブラウザのみを対象とするのであれば、シンプルに対応できるものであろうと思います。もし、より高いセキュリティを求める場合は、追加でその要件に合わせた実装等の検討を進めれば良いでしょう。(悪意を持った第三者向けには追加の対策が必要となるかもしれませんが、カジュアルにiframeで自サイトを埋め込む第三者への対策としては、これで十分であろうと思います)

サンプルコード

以下では処理が把握しやすいよう、便宜的にインラインでJavaScriptを記述していますが、別ファイルにして難読化した方が良いでしょう。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="notify">
        <p>NG:不正なドメインからリクエストが行われました</p>
    </div>
    <div id="main" style="display:none !important;">
        <p>正規のドメインで表示されるコンテンツ</p>
    </div>
    <script>
        const elemMain = document.getElementById('main');
        const elemNotify = document.getElementById('notify');
        try {
                if (parent.location.href.match(/^https:\/\/www\.example\.com/)){
                        elemNotify.innerHTML = 'OK:正規のドメインからリクエストが行われました';
                        elemMain.style.display = 'block';
                } else {
                        throw new Error();
                }
        } catch(e) {
                elemMain.innerHTML = '';
        }
    </script>
</body>

実行結果

正規のドメインからのリクエスト

image.png

不正なドメインからのリクエスト(JavaScriptが無効化されている場合を含む)

image.png

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2