web-dev-qa-db-ja.com

Webページがiframe内に読み込まれているのか、ブラウザウィンドウに直接読み込まれているのかを識別する方法

私はiframeベースのFacebookアプリを書いています。今私は普通のウェブサイトと同様にフェイスブック内のキャンバスページをレンダリングするのに同じhtmlページを使いたいです。ページがiframe内に読み込まれたのか、ブラウザに直接読み込まれたのかを判断できますか。

518
akshat

同じOriginポリシー により、ブラウザはwindow.topへのアクセスをブロックすることができます。 IEバグも発生しています。これが実用的なコードです:

function inIframe () {
    try {
        return window.self !== window.top;
    } catch (e) {
        return true;
    }
}

topselfは両方とも(windowと共に)parentオブジェクトであるため、自分のウィンドウが一番上のウィンドウかどうかがわかります。

978
Greg

親と同じOrigin上のiframe内にある場合、 window.frameElement メソッドは、ウィンドウが埋め込まれている要素(例:iframeまたはobject)を返します。それ以外の場合、トップレベルのコンテキストでブラウズしている場合、または親フレームと子フレームの起源が異なる場合は、nullと評価されます。

window.frameElement
  ? 'embedded in iframe or object'
  : 'not embedded or cross-Origin'

これは HTML標準 で、最近のすべてのブラウザで基本的にサポートされています。

78

RoBorgは正しいですが、私はサイドノートを追加したいと思いました。

IE7/IE8では、マイクロソフトがブラウザにタブを追加したとき、注意していないとJSが混乱を招くことになります。

このページレイアウトを想像してみてください。

MainPage.html
  IframedPage1.html   (named "foo")
  IframedPage2.html   (named "bar")
    IframedPage3.html (named "baz")

フレーム "baz"でリンクをクリックすると(ターゲットなし、 "baz"フレームにロードされます)、正常に動作します。

ロードされたページが、special.htmlと呼んで、それを "it"が "bar"という名前の親フレームを持っているかどうかをチェックするためにJSを使用するならば、それはtrueを返します(期待される)。

今度は、special.htmlページがロードされると、親フレームの存在と名前をチェックし、 "bar"の場合はそれ自身をbarフレームに再ロードします。

if(window.parent && window.parent.name == 'bar'){
  window.parent.location = self.location;
}

ここまでは順調ですね。今バグが来ます。

通常のように元のリンクをクリックして "baz"フレームにspecial.htmlページをロードする代わりに、中央をクリックするか、新しいタブで開くことを選択できます

その新しいタブが親フレームなしで(をロードすると!IEはページロードの無限ループに入ります!は、IEがJavaScriptのフレーム構造を「コピー」して、新しいタブに親があり、その親に「bar」という名前が付いているためです。

良いニュースは、そのチェックです:

if(self == top){
  //this returns true!
}

その新しいタブではtrueを返すので、この奇妙な条件をテストすることができます。

25
scunliffe

受け入れられた答えはFirefox 6.0拡張(Addon-SDK 1.0)の内容スクリプトの中で私のために働きませんでした:Firefoxはそれぞれトップレベルウィンドウとすべてのiframeで内容スクリプトを実行します。

コンテンツスクリプト内では、次のような結果が得られます。

 (window !== window.top) : false 
 (window.self !== window.top) : true

この出力の奇妙な点は、コードがiframe内で実行されているかトップレベルウィンドウ内で実行されているかにかかわらず、常に同じことです。

一方、Google Chromeはトップレベルウィンドウ内でコンテンツスクリプトを1回しか実行しないようであるため、上記はまったく機能しません。

両方のブラウザのコンテンツスクリプトで私のために最後に働いたのはこれです:

 console.log(window.frames.length + ':' + parent.frames.length);

Iframeがなければ、これは0:0を出力し、1つのフレームを含むトップレベルウィンドウでは1:1を出力し、ドキュメントの唯一のiframeでは0:1を出力します。

これにより、私の拡張機能は両方のブラウザでiframeが存在するかどうかを判断し、さらにFirefoxではiframeの1つの内部で実行されているかどうかを判断できます。

18
magnoz

この例が以前のWebブラウザでどのように機能するかはわかりませんが、IE、Firefox、およびChromeで問題なく使用しています。

var iFrameDetection = (window === window.parent) ? false : true;
7

私はこれを使っています:

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);
5
mikewolf78

これを実現する方法の例として、このJavaScript関数を使用してください。

function isNoIframeOrIframeInMyHost() {
// Validation: it must be loaded as the top page, or if it is loaded in an iframe 
// then it must be embedded in my own domain.
// Info: IF top.location.href is not accessible THEN it is embedded in an iframe 
// and the domains are different.
var myresult = true;
try {
    var tophref = top.location.href;
    var tophostname = top.location.hostname.toString();
    var myhref = location.href;
    if (tophref === myhref) {
        myresult = true;
    } else if (tophostname !== "www.yourdomain.com") {
        myresult = false;
    }
} catch (error) { 
  // error is a permission error that top.location.href is not accessible 
  // (which means parent domain <> iframe domain)!
    myresult = false;
}
return myresult;
}
2
Rolf

私は実際にwindow.parentをチェックするのに使用し、それは私のために働いたが、最近のwindowは巡回オブジェクトであり、常に親キー、iframeを持っているか、またはiframeを持たない。

コメントが示唆するように、window.parentとの比較はうまくいきます。 iframeが親とまったく同じWebページである場合、これが機能するかどうかわからない。

window === window.parent;
1
Jabran Saeed

今すぐ使えるレガシブラウザフレームブレイキングスクリプト

他の解決策は私にはうまくいきませんでした。これはすべてのブラウザで動作します。

クリックジャッキングに対して防御する1つの方法は、フレームに入れてはいけない各ページに「フレームブレーカー」スクリプトを含めることです。次の方法論は、X-Frame-Options-HeaderをサポートしていないレガシブラウザであってもWebページがフレーム化されるのを防ぎます。

Document HEAD要素に、以下を追加します。

<style id="antiClickjack">body{display:none !important;}</style>

まず、スタイル要素自体にIDを適用します。

<script type="text/javascript">
   if (self === top) {
       var antiClickjack = document.getElementById("antiClickjack");
       antiClickjack.parentNode.removeChild(antiClickjack);
   } else {
       top.location = self.location;
   }
</script>

こうすることで、すべてをドキュメント[HEADに含めることができ、APIに必要なメソッド/タグライブラリは1つだけになります。

参照: https://www.codemagi.com/blog/post/194

1
Albert Olivé

あなたはFacebookのアプリのコンテキストで尋ねているので、あなたは最初のリクエストが行われたときにサーバーでこれを検出することを検討したいかもしれません。それがiframeから呼び出された場合、Facebookはfb_sig_userキーを含む一連のクエリ文字列データを渡します。

おそらくこのデータをアプリケーションでチェックして使用する必要があるので、それを使用してレンダリングに適切なコンテキストを決定します。

1
HectorMac

これが私にとって最も簡単な解決策となりました。

    <p id="demofsdfsdfs"></p>

<script>

if(window.self !== window.top) {

//run this code if in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "in frame";

}else{

//run code if not in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "no frame";
}

</script>
0
Alex Roseland