SecurityError:originのあるフレームがcross-origin frameにアクセスするのをブロックしました


556

<iframe>HTMLページにを読み込んで、JavaScriptを使用してページ内の要素にアクセスしようとしていますが、コードを実行しようとすると、次のエラーが発生します。

SecurityError: Blocked a frame with origin "http://www.<domain>.com" from accessing a cross-origin frame.

フレーム内の要素にアクセスできるように、解決策を見つけるのを手伝っていただけませんか?

私はこのコードをテストに使用していますが、無駄です:

$(document).ready(function() {
    var iframeWindow = document.getElementById("my-iframe-id").contentWindow;

    iframeWindow.addEventListener("load", function() {
        var doc = iframe.contentDocument || iframe.contentWindow.document;
        var target = doc.getElementById("my-target-id");

        target.innerHTML = "Found it!";
    });
});

回答:


821

同一生成元ポリシー

JavaScriptを使用して別のオリジンのにアクセスすることはできません。アクセスできる<iframe>としたら、セキュリティ上の大きな欠陥になります。同じ生成元のポリシーの 場合、ブラウザは、異なる生成元のフレームにアクセスしようとするスクリプトをブロックします

アドレスの次の部分の少なくとも1つが維持されていない場合、オリジンは異なると見なされます。

<protocol>://<hostname>:<port>/...

フレームにアクセスする場合は、プロトコルホスト名ポートがドメインと同じである必要があります。

注:Internet Explorerはこのルールに厳密に従っていないことがわかっています。詳細については、こちらを参照してください。

ここから、次のURLにアクセスしようとするとどうなるでしょうか。 http://www.example.com/home/index.html

URL                                             RESULT 
http://www.example.com/home/other.html       -> Success 
http://www.example.com/dir/inner/another.php -> Success 
http://www.example.com:80                    -> Success (default port for HTTP) 
http://www.example.com:2251                  -> Failure: different port 
http://data.example.com/dir/other.html       -> Failure: different hostname 
https://www.example.com/home/index.html:80   -> Failure: different protocol
ftp://www.example.com:21                     -> Failure: different protocol & port 
https://google.com/search?q=james+bond       -> Failure: different protocol, port & hostname 

回避策

同一生成元ポリシーは、スクリプトが異なる生成元のサイトのコンテンツにアクセスするのをブロックしますが、両方のページを所有している場合は、この問題を回避しwindow.postMessage、その相対messageイベント使用して、次のように2つのページ間でメッセージを送信できます。

  • メインページ:

    let frame = document.getElementById('your-frame-id');
    frame.contentWindow.postMessage(/*any variable or object here*/, 'http://your-second-site.com');

    への2番目の引数は、宛先の起点に関する優先順位がないpostMessage()こと'*'を示すことです。他のサイトに送信するデータを開示しないように、可能な場合は常にターゲットオリジンを提供する必要があります。

  • あなたの<iframe>(メインページに含まれています):

    window.addEventListener('message', event => {
        // IMPORTANT: check the origin of the data! 
        if (event.origin.startsWith('http://your-first-site.com')) { 
            // The data was sent from your site.
            // Data sent with postMessage is stored in event.data:
            console.log(event.data); 
        } else {
            // The data was NOT sent from your site! 
            // Be careful! Do not use it. This else branch is
            // here just for clarity, you usually shouldn't need it.
            return; 
        } 
    }); 

このメソッドは双方向に適用でき、メインページでリスナーを作成し、フレームから応答を受信します。同じロジックを、ポップアップや、メインページによって生成された新しいウィンドウ(たとえば、を使用してwindow.open())に実装することもできます。違いはありません。

ブラウザーで同一生成元ポリシーを無効にする

このトピックにはすでにいくつかの良い答えがあります(私はそれらをグーグルで見つけただけです)。そのため、これが可能なブラウザーについては、相対的な答えをリンクします。ただし、同一生成元ポリシー無効にするとブラウザにのみ影響することに注意してください。また、同一生成元のセキュリティ設定を無効に助成金でブラウザを実行している任意のようにクロスオリジンリソースへのウェブサイトへのアクセスを、それは非常に危険なのです、あなたは、あなたがやっている内容を正確に把握していない場合(例えば開発目的)行われません


27
その他の答え私が見つけた12を、CORSが/ことを示唆しているAccess-Control-Allow-Originだけに、のiFrameには適用されませんXHRs、フォント、WebGLのとcanvas.drawImagepostMessage唯一の選択肢だと思います。
snappieT 2015年

369
JavaScriptでチルダ「〜」演算子を初めて見ました。それが何をするのかも知らない他の人のために:-1を0に変換します。これにより、indexOfの結果に対して "!= -1"を実行する必要がなくなります。個人的には、 "!= -1"を使用することを続けると思います。他のプログラマーがチルドを入れ忘れることから生じるバグを理解し、回避するのが容易だからです(ただし、何か新しいことを学ぶのはいつでもいいです)。
Redzarf 2015年

4
@SabaAhangはを確認するだけiframe.srcです。サイトがドメインのホスト名と異なる場合は、そのフレームにアクセスできません。
Marco Bonelli、2015年

18
@Snuggsは完全に間違っており~、数値の2の補数を返すため、にnなります-n-1。つまり、のみ-1となり0(と解釈されますfalse)、その他の値はテストに合格します。IE 0 = -(-1)-1ではなく-(-1+1)
Marco Bonelli、2016年

2
@ user2568374 location.ancestorOrigins[0]は親フレームの場所です。あなたのフレームが内部で実行されている場合は、別のサイトに、あなたが使用してチェックしevent.origin.indexOf(location.ancestorOrigins[0])、イベントの原点が親のフレームアドレス、含まれている場合はチェックしている常にあることを行っているtrueので、あなたが許可されている、いずれかの親を持つ任意の起源を、これをあなたのフレームにアクセスするために、そして明らかにあなたがやりたいことではありません。さらに、document.referrer上記のコメントですでに説明したように、これも悪い習慣です。
マルコボネーリ

55

Marco Bonelliの答えを補完する:フレーム/ iframe間でやり取りする現在の最良の方法は、すべてのブラウザーwindow.postMessageサポートされているを使用することです。


21
このリンクで質問に答えることができますが、回答の重要な部分をここに含め、参照用のリンクを提供することをお勧めします。リンクされたページが変更されると、リンクのみの回答が無効になる可能性があります。- レビューから
アレッサンドロカッティン

9
同意しません、@ AlessandroCuttin。どのようにwindow.postMessage機能するかを説明すると、私がすでに参照している承認済みの回答のみが複製されます。さらに、私の答えが追加する本質的な価値は、正確に外部ドキュメントを参照することです。
Geert

5
承認された回答を編集してそこに追加できれば、より良いと思います
Martin Massera

12
親(HTMLページ)と子要素(他のドメインiframe)の両方にアクセスできる場合にのみ使用できるwindow.postMessage。それ以外の場合は、「可能性はありません」というエラーが常にスローされます「キャッチされないDOMException:ブロックされたフレームオリジン "< yourdomainname.com >"を使用して、クロスオリジンフレームにアクセスできません。 "
VIJAY P 2017

19

ドメインのWebサーバーのhttp://www.<domain>.com構成を確認します。X-Frame-Options これはクリックジャッキング攻撃を防ぐために設計されたセキュリティ機能です。

clickJackingはどのように機能しますか?

  1. 邪悪なページは、被害者のページとまったく同じように見えます。
  2. 次に、ユーザーをだましてユーザー名とパスワードを入力させました。

技術的には、悪にはiframe犠牲者ページへのソースがあります。

<html>
    <iframe src='victim_domain.com'/>
    <input id="username" type="text" style="display: none;/>
    <input id="password" type="text" style="display: none;/>
    <script>
        //some JS code that click jacking the user username and input from inside the iframe...
    <script/>
<html>

セキュリティ機能のしくみ

Webサーバーリクエストがレンダリング内にレンダリングされないようにする場合はiframex-frame-optionsを追加します

X-Frame-Options DENY

オプションは次のとおりです。

  1. SAMEORIGIN //自分のドメインにのみ許可して、iframe内にHTMLをレンダリングします。
  2. DENY // HTMLをiframe内でレンダリングすることを許可しない
  3. "ALLOW-FROM https://example.com/ " //特定のドメインがiframe内にHTMLをレンダリングできるようにする

これはIIS構成の例です。

   <httpProtocol>
       <customHeaders>
           <add name="X-Frame-Options" value="SAMEORIGIN" />
       </customHeaders>
   </httpProtocol>

質問の解決策

Webサーバーがセキュリティ機能をアクティブにした場合、クライアント側のSecurityErrorが発生する可能性があります。


1
X-Frame-Optionsがここに適用されるとは思わない-ゲスト(埋め込み)ページによって定義されたX-Frame-Optionsは、親がページをロードすることを拒否する可能性がありますが、私の知る限り、JavaScriptには影響しませんアクセス-X-Frame-Options:*でも、javascriptを使用して別のオリジンゲストページのDOMにアクセスできないと思います
Noah Gilmore

13

私にとっては、双方向のハンドシェイクを実装したかった:
-親ウィンドウはiframeよりも速くロードされる-iframe は準備ができ
次第親ウィンドウと通信する必要がある
-親はiframeメッセージを受信して​​再生する準備ができている

このコードは、[CSSカスタムプロパティ]
コードを使用してiframeにホワイトラベルを設定するために使用されます:
iframe

$(function() {
    window.onload = function() {
        // create listener
        function receiveMessage(e) {
            document.documentElement.style.setProperty('--header_bg', e.data.wl.header_bg);
            document.documentElement.style.setProperty('--header_text', e.data.wl.header_text);
            document.documentElement.style.setProperty('--button_bg', e.data.wl.button_bg);
            //alert(e.data.data.header_bg);
        }
        window.addEventListener('message', receiveMessage);
        // call parent
        parent.postMessage("GetWhiteLabel","*");
    }
});

$(function() {
    // create listener
    var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
    var eventer = window[eventMethod];
    var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
    eventer(messageEvent, function (e) {
        // replay to child (iframe) 
        document.getElementById('wrapper-iframe').contentWindow.postMessage(
            {
                event_id: 'white_label_message',
                wl: {
                    header_bg: $('#Header').css('background-color'),
                    header_text: $('#Header .HoverMenu a').css('color'),
                    button_bg: $('#Header .HoverMenu a').css('background-color')
                }
            },
            '*'
        );
    }, false);
});

当然のことながら、
出所とテキストを制限できます。これは作業が簡単なコードで、この例が役立つことがわかりました:[ postMessageを使用した
クロスドメインメッセージング]


iframeのドキュメントが親ページよりも後にJSを実行しているため、iframeのドキュメントがメッセージをリスニングする前にメッセージが送信されるという、Safariの問題を処理しています。これは、chromeやfirefoxが行うこととは正反対です-iOSのサファリでコードをテストしましたか?btw postMessageの2番目のパラメータの値が "*"の場合、安全ではありません。常にドメインを指定する必要があります
sKopheK

最初のコードブロックは、親のiframeにありますか、それともiframeに読み込まれるページにありますか?
Demonic218

0

これに影響を与える可能性のあるJava Spring固有の構成を追加したいと思います。

Webサイトまたはゲートウェイアプリケーションには、contentSecurityPolicy設定があります。

Springでは、WebSecurityConfigurerAdapterサブクラスの実装を見つけることができます

contentSecurityPolicy("
script-src 'self' [URLDomain]/scripts ; 
style-src 'self' [URLDomain]/styles;
frame-src 'self' [URLDomain]/frameUrl...

...

.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)

ここで安全な外部インターネットを定義していない場合、ブラウザはブロックされます。


0

iframeのコンテンツを制御できる場合(つまり、Amazon Mechanical Turkなどのクロスオリジン設定でロードされるだけの場合)は<body onload='my_func(my_arg)'>、内部htmlの属性でこの問題を回避できます。

たとえば、内側のhtmlの場合、thishtmlパラメータを使用します(はい- thisが定義されていて、内側のbody要素の親ウィンドウを参照しています)。

<body onload='changeForm(this)'>

内側のhtmlで:

    function changeForm(window) {
        console.log('inner window loaded: do whatever you want with the inner html');
        window.document.getElementById('mturk_form').style.display = 'none';
    </script>

-25
  • スタートメニューを開く
  • windows + Rと入力するか、「実行
  • 以下のコマンドを実行します。

chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security


3
迅速で汚れたテストに最適!
user1068352 2018年

6
迅速で汚いテストではなく、受け入れられた回答ですでに対処しているものはすべてひどい。
クエンティン

2
コマンドを使用しても、Chromeはこの方法でWebセキュリティを無効にしないため、機能しません
Metafaniel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.