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


597

私はiframeベースのFacebookアプリを書いています。次に、同じHTMLページを使用して、Facebook内の通常のWebサイトとキャンバスページをレンダリングします。ページがiframe内に読み込まれたか、ブラウザーに直接読み込まれたかを確認できるかどうか知りたいですか?


2
いくつかの良い方法(コメントを含む):tommcfarlin.com/check-if-a-page-is-in-an-iframe
simhumileco

回答:


1108

同じ発信元ポリシーwindow.topにより、ブラウザはへのアクセスをブロックできます。IEのバグも発生します。ここに作業コードがあります:

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

topselfは両方ともwindow(と共にparent)オブジェクトなので、ウィンドウがトップウィンドウかどうかがわかります。


4
これはFirefoxでは正常に動作するようです。他のブラウザでも動作しますか?
akshat 2008年

5
iframe内にiframeが含まれるページを作成し、親のiframeがページに
埋め込ま

7
@sglessard子ページと親が異なるドメインからのものである場合、Firefoxは同じ生成元ポリシー(www.w3.org/Security/wiki/Same_Origin_Policy)に対して不満を示し、コードは機能しません
Gaurang Jadia

18
これはIE 11、10、および9で機能します。また、FFやOpera、そしてもちろんChromeでも動作します。まだ問題は発生していません。
jeremysawesome 2013

4
1995年の最新の技術をまだ揺るがしていない人にとっては、またはのコンテンツから実行するとwindow.self !== window.top戻ります。trueframe iframe
Jeromyフランス語2017

84

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

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

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


2
W3CframeElementによれば、読み取りを試みるとクロスオリジンのiframeでSecurityError例外がスローされることに注意してください(WHATWGは代わりにnullを返す必要があると言っています)。したがって、ステートメント内にラップすることができます。try...catch
Oriol

5
取得nullの内側と外側iframe
OlehZiniak

4
MDNの説明によると、「埋め込まれているドキュメントの出所が異なる場合(別のドメインから検索された場合など)、これはnullです。」
xeophin

リターンがどうあるべきかを明確にするために:Returns the element (such as <iframe> or <object>) in which the window is embedded, or null if the element is either top-level or is embedded into a document with a different script origin; that is, in cross-origin situations.
Art3mix

26

RoBorgは正しいですが、私は付記を付けたかったです。

IE7 / IE8では、Microsoftがブラウザにタブを追加したときに、注意を怠るとJSに大混乱を引き起こす1つの問題が発生しました。

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

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

フレーム "baz"でリンクをクリックします(ターゲットがなく、 "baz"フレームに読み込まれます)。

ロードされたページがspecial.htmlと呼ばれる場合、JSを使用して、「it」に「bar」という名前の親フレームがあるかどうかを確認します。この場合、trueが返されます(予期されています)。

次に、special.htmlページが読み込まれたときに、親フレームをチェックし(存在とその名前を確認し、 "bar"の場合はそれ自体をバーフレームに再読み込みします)。

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

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

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

その新しいタブが読み込まれると(親フレームはまったくありません!IEはページ読み込みの無限ループに入ります!IEはJavaScriptのフレーム構造を「コピー」して、新しいタブには親があり、その親には「バー」という名前があるためです。

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

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

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


その間にバグは修正されましたか?IE8では再現できません。私はいつも正しいwindow.parentです。
user123444555621

1
よくわかりません-テストスイートをIE9以下に対して再度実行し、更新を投稿します。
scunliffe 2012

18

受け入れられた回答が、Firefox 6.0 Extension(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が存在する場合は両方のブラウザーで、さらにiframeの1つ内で実行されている場合はFirefoxで判別できます。


1
document.defaultView.self === document.defaultView.topまたはを試してくださいwindow !== window.top。FirefoxのアドオンSDKのコンテンツスクリプトでは、グローバルselfオブジェクトはメインスクリプトとの通信に使用されるオブジェクトです。
Rob W

13

この例が古いWebブラウザーでどのように機能するかはわかりませんが、IE、Firefox、Chromeでこれを使用すると問題が発生しません。

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

6
または単に!(window===window.parent)
CalculatorFeline

11
window!== window.parent
Ivan Leonenko

5

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

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

なぜこれを行うの.indexOf("HTMLIFrameElement")ですか?
ルーク

.indexOf( 'foobarbaz')> -1は、正規表現を使用せずに、「部分文字列の一致」(つまり、「foobarbaz」が文字列内のどこかにあるか?)を確認する方法です。論理的には.match(/ foobarbaz /)と同等です。これは(以前は:-)幅広いブラウザーで動作しますが、それでも、習慣から、または正規表現機構のパフォーマンスに対する懸念のために使用される可能性があります。
チャックコラーズ2013

2

これを実現する方法の例として、この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

現時点でのレガシーブラウザフレームブレークスクリプト

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

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

ドキュメントの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で必要なメソッド/ taglibは1つだけです。

リファレンス:https : //www.codemagi.com/blog/post/194


1
フレーミングが唯一の脅威ではありません、(iframeタグを置き換えるHTML5オブジェクトタグを使用して意味する)異議について..私はそれ..に対してこの仕事しません何を考える
レイモンドNijland

2
if ( window.location !== window.parent.location ) 
{
      // The page is in an iframe   
} 
else 
{     
      // The page is not in an iframe   
}

1

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

おそらくアプリでこのデータを確認して使用する必要があるため、レンダリングに適切なコンテキストを決定するためにそれを使用してください。


1

私は実際にwindow.parentをチェックして使用しましたが、最近はwindowが循環オブジェクトであり、常に親キー、iframeまたはiframeがありません。

コメントがwindow.parentと比較することは難しいことを示唆しています。iframeが親とまったく同じWebページである場合、これが機能するかどうかはわかりません。

window === window.parent;

メインウィンドウコンテキストのクロムでwindow.parent === windowはtrueです。だからあなたの答えは間違っています。そして、この比較はチェックに使用できます(少なくともChromeでは、別のブラウザーでテストしていませんでした)。
MarkosyanArtur 2017

iFrameのコンテキストでは機能しませんが、 `if(window === window.parent){`は機能します。それが機能しない理由がわからないので、私はあなたをマークダウンしていません
www-0av-Com

-1

それは私が数回使用した古代のコードです:

if (parent.location.href == self.location.href) {
    window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}

エネコアロンソに追加するには:これは機能します(parent.location == self.location)
piotr_cz

@piotr_cz、同じオリジンポリシーがへのアクセスを許可する場合にのみ機能しparent.locationます。それ以外の場合は例外がスローされます
Dan

-1

ユーザーがFacebookページのタブまたはキャンバスからアプリにアクセスしているかどうかを知りたい場合は、署名付きリクエストを確認してください。それを取得しない場合、おそらくユーザーはFacebookからアクセスしていません。signed_requestフィールドの構造とフィールドの内容を確認するため。

php-sdkを使用すると、次のような署名付きリクエストを取得できます。

$signed_request = $facebook->getSignedRequest();

署名付きリクエストの詳細については、こちらをご覧ください。

https://developers.facebook.com/docs/reference/php/facebook-getSignedRequest/

そしてここ:

https://developers.facebook.com/docs/reference/login/signed-request/


-1

これは私にとって最も簡単な解決策でした。

    <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>

-4
if (window.frames.length != parent.frames.length) { page loaded in iframe }

ただし、ページとiframeにロードしているページでiframeの数が異なる場合のみ。このコードの結果が100%保証されるように、ページにiframeを作成しないでください


ウィンドウがiframe内にあるかどうかを判断するための非常に洗練されたソリューションではありません。また、parent.framesから読み取ることができる保証もありません。
パーシー

-4

このJavaScriptを各ページに記述します

if (self == top)
  { window.location = "Home.aspx"; }

その後、自動的にホームページにリダイレクトされます。


4
ifでない場合、リダイレクトは機能します。だから私はあなたのサイトをナビゲートすることはできません。次に、親ページからのリダイレクトを防ぐための手法が存在します。
MariusBalčytis2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.