Wie kann man feststellen, ob eine Webseite in einem Iframe oder direkt in das Browserfenster geladen wird?

597

Ich schreibe eine iframe-basierte Facebook-App. Jetzt möchte ich dieselbe HTML-Seite verwenden, um die normale Website sowie die Canvas-Seite in Facebook zu rendern. Ich möchte wissen, ob ich feststellen kann, ob die Seite im Iframe oder direkt im Browser geladen wurde.

Akshat
quelle
2
Ein paar nette Möglichkeiten (einschließlich Kommentare): tommcfarlin.com/check-if-a-page-is-in-an-iframe
simhumileco

Antworten:

1108

Browser können den Zugriff window.topaufgrund derselben Ursprungsrichtlinie blockieren . IE-Fehler treten ebenfalls auf. Hier ist der Arbeitscode:

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

topund selfsind beide windowObjekte (zusammen mit parent), sodass Sie sehen, ob Ihr Fenster das oberste Fenster ist.

Greg
quelle
4
Dies scheint in Firefox gut zu funktionieren. Funktioniert es auch in anderen Browsern?
Akshat
5
Nachdem ich eine Seite mit einem Iframe innerhalb eines Iframes hatte, um von meinem untergeordneten
Iframe
7
@sglessard Wenn die untergeordnete Seite und die übergeordnete Seite aus verschiedenen Domänen stammen, beschwert sich Firefox über die Richtlinie für denselben Ursprung (www.w3.org/Security/wiki/Same_Origin_Policy) und der Code funktioniert nicht
Gaurang Jadia
18
Dies funktioniert in IE 11, 10 und 9 für mich. Es funktioniert auch in FF und Opera sowie natürlich in Chrome. Ich habe keine Probleme damit.
jeremysawesome
4
Für diejenigen , die noch die letzten im Jahr 1995 Tech - rocking, window.self !== window.topkehrt truebei der Ausführung aus Inhalten frame, oder iframe .
Jeromy French
84

In einem Iframe mit demselben Ursprung wie das übergeordnete window.frameElementElement gibt die Methode das Element (z. B. iframeoder object) zurück, in das das Fenster eingebettet ist. Andernfalls wird beim Surfen in einem Kontext der obersten Ebene oder wenn der übergeordnete und der untergeordnete Frame unterschiedliche Ursprünge haben, eine Auswertung durchgeführt null.

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

Dies ist ein HTML-Standard mit grundlegender Unterstützung in allen modernen Browsern.

Konstantin Smolyanin
quelle
2
Beachten Sie, dass beim Versuch zu lesen frameElementlaut W3C eine SecurityError-Ausnahme in Ursprungs-übergreifenden Iframes ausgelöst wird ( WHATWG sagt, dass stattdessen null zurückgegeben werden sollte). Vielleicht möchten Sie es in eine try...catchAnweisung einschließen.
Oriol
5
immer nullinnen und außeniframe
OlehZiniak
4
In der Beschreibung bei MDN heißt es: "Wenn das Dokument, in das es eingebettet ist, einen anderen Ursprung hat (z. B. aus einer anderen Domäne stammt), ist dies null."
Xeophin
Nur um zu klären, wie die Rückkehr aussehen soll: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 ist korrekt, aber ich wollte eine Randnotiz hinzufügen.

In IE7 / IE8 haben Microsoft beim Hinzufügen von Tabs zu ihrem Browser eine Sache kaputt gemacht, die Ihrem JS Schaden zufügt, wenn Sie nicht vorsichtig sind.

Stellen Sie sich dieses Seitenlayout vor:

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

Jetzt klicken Sie in Frame "baz" auf einen Link (kein Ziel, lädt in den "baz" Frame), es funktioniert einwandfrei.

Wenn die Seite, die geladen wird, als special.html bezeichnet wird, verwendet JS, um zu überprüfen, ob "es" einen übergeordneten Frame mit dem Namen "bar" hat, wird true (erwartet) zurückgegeben.

Nehmen wir nun an, dass die Seite special.html beim Laden den übergeordneten Frame überprüft (auf Existenz und Namen, und wenn es sich um "Balken" handelt, lädt sie sich selbst in den Balkenrahmen neu, z

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

So weit, ist es gut. Jetzt kommt der Fehler.

Nehmen wir an, Sie klicken nicht wie gewohnt auf den ursprünglichen Link und laden die Seite special.html in den Rahmen "baz", sondern haben mit der mittleren Maustaste darauf geklickt oder sie in einem neuen Tab geöffnet.

Wenn dieser neue Tab geladen wird ( ohne übergeordnete Frames! ), Tritt der IE in eine endlose Schleife des Seitenladens ein! weil IE die Rahmenstruktur in JavaScript "kopiert", so dass die neue Registerkarte ein übergeordnetes Element hat und dieses übergeordnete Element den Namen "bar" hat.

Die gute Nachricht ist, dass überprüft wird:

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

In dieser neuen Registerkarte wird true zurückgegeben, und Sie können diese ungerade Bedingung testen.

scunliffe
quelle
Wurde der Fehler inzwischen behoben? Ich kann es nicht in IE8 reproduzieren. Ich bekomme immer das Richtige window.parent.
user123444555621
1
Ich bin mir nicht sicher - ich werde meine Testsuite erneut gegen IE9 und darunter ausführen und ein Update veröffentlichen.
Scunliffe
18

Die akzeptierte Antwort hat bei mir im Inhaltsskript einer Firefox 6.0-Erweiterung (Addon-SDK 1.0) nicht funktioniert: Firefox führt das Inhaltsskript in jedem Fenster der obersten Ebene und in allen Iframes aus.

Im Inhaltsskript erhalte ich folgende Ergebnisse:

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

Das Seltsame an dieser Ausgabe ist, dass sie immer gleich ist, unabhängig davon, ob der Code in einem Iframe oder im Fenster der obersten Ebene ausgeführt wird.

Auf der anderen Seite scheint Google Chrome mein Inhaltsskript nur einmal im Fenster der obersten Ebene auszuführen, sodass das oben genannte überhaupt nicht funktioniert.

Was für mich in einem Inhaltsskript in beiden Browsern endlich funktioniert hat, ist Folgendes:

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

Ohne Iframes wird dies gedruckt 0:0, in einem Fenster der obersten Ebene, das einen Frame enthält 1:1, und im einzigen Iframe eines Dokuments, das gedruckt wird 0:1.

Dadurch kann meine Erweiterung in beiden Browsern feststellen, ob Iframes vorhanden sind, und zusätzlich in Firefox, ob sie in einem der Iframes ausgeführt wird.

Magnoz
quelle
1
Versuchen Sie es document.defaultView.self === document.defaultView.topoder window !== window.top. Im Inhaltsskript des Firefox-Add-On-SDK ist das globale selfObjekt ein Objekt, das zur Kommunikation mit dem Hauptskript verwendet wird.
Rob W
13

Ich bin nicht sicher, wie dieses Beispiel für ältere Webbrowser funktioniert, aber ich verwende es für IE, Firefox und Chrome ohne und ohne Probleme:

var iFrameDetection = (window === window.parent) ? false : true;
Portal TheAnGeLs
quelle
6
Oder einfach!(window===window.parent)
CalculatorFeline
11
window! == window.parent
Ivan Leonenko
5

Ich benutze dies:

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);
mikewolf78
quelle
Warum machst du das : .indexOf("HTMLIFrameElement")?
Luke
.indexOf ('foobarbaz')> -1 ist eine Möglichkeit, nach "Teilzeichenfolgenübereinstimmung" zu suchen (dh kann 'foobarbaz' irgendwo in der Zeichenfolge gefunden werden?), jedoch ohne Verwendung regulärer Ausdrücke. Es ist logisch äquivalent zu .match (/ foobarbaz /). Es (früher :-) funktioniert mit einer größeren Anzahl von Browsern und kann immer noch entweder aus Gewohnheit oder aus Angst vor der Leistung von Maschinen für reguläre Ausdrücke verwendet werden.
Chuck Kollars
2

Verwenden Sie diese Javascript-Funktion als Beispiel, um dies zu erreichen.

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;
}
Rolf
quelle
2

Das derzeit beste Legacy-Browser-Frame-Breaking-Skript

Die anderen Lösungen haben bei mir nicht funktioniert. Dieser funktioniert in allen Browsern:

Eine Möglichkeit, sich gegen Clickjacking zu verteidigen, besteht darin, auf jeder Seite ein "Frame-Breaker" -Skript einzufügen, das nicht eingerahmt werden sollte. Die folgende Methode verhindert, dass eine Webseite auch in älteren Browsern eingerahmt wird, die den X-Frame-Options-Header nicht unterstützen.

Fügen Sie im Dokument HEAD-Element Folgendes hinzu:

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

Wenden Sie zuerst eine ID auf das Stilelement selbst an:

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

Auf diese Weise kann sich alles im Dokument HEAD befinden und Sie benötigen nur eine Methode / Taglib in Ihrer API.

Referenz: https://www.codemagi.com/blog/post/194

Albert Olivé
quelle
1
Framing ist nicht die einzige Bedrohung, was ist mit Einwänden (was bedeutet, dass ein HTML5-Objekt-Tag verwendet wird, das das Iframe-Tag ersetzt). Ich denke, das wird nicht dagegen funktionieren.
Raymond Nijland
2
if ( window.location !== window.parent.location ) 
{
      // The page is in an iframe   
} 
else 
{     
      // The page is not in an iframe   
}
Wilhelm
quelle
1

Da Sie im Kontext einer Facebook-App nachfragen, sollten Sie dies möglicherweise auf dem Server erkennen, wenn die erste Anforderung gestellt wird. Facebook gibt eine Reihe von Querystring-Daten weiter, einschließlich des Schlüssels fb_sig_user, wenn dieser von einem Iframe aufgerufen wird.

Da Sie diese Daten wahrscheinlich ohnehin in Ihrer App überprüfen und verwenden müssen, bestimmen Sie damit den geeigneten Kontext für das Rendern.

HectorMac
quelle
1

Eigentlich habe ich window.parent überprüft und es hat bei mir funktioniert, aber in letzter Zeit ist window ein zyklisches Objekt und hat immer einen übergeordneten Schlüssel, einen Iframe oder keinen Iframe.

Wie aus den Kommentaren hervorgeht, funktioniert der Vergleich mit window.parent schwierig. Ich bin mir nicht sicher, ob dies funktioniert, wenn iframe genau dieselbe Webseite wie das übergeordnete ist.

window === window.parent;
Jabran Saeed
quelle
in Chrome im Hauptfenster Kontext window.parent === windowist wahr. Ihre Antwort ist also falsch. Und dieser Vergleich könnte zur Überprüfung verwendet werden (zumindest in Chrom, nicht in einem anderen Browser getestet).
MarkosyanArtur
FUNKTIONIERT NICHT im Kontext von iFrame, aber `if (window === window.parent) {` funktioniert. Ich markiere Sie nicht, da ich nicht weiß, warum es nicht funktioniert
www-0av-Com
-1

Es ist ein uralter Code, den ich einige Male verwendet habe:

if (parent.location.href == self.location.href) {
    window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}
Fehler601
quelle
Um zu Eneko Alonso hinzuzufügen: das funktioniert(parent.location == self.location)
piotr_cz
@piotr_cz, funktioniert nur, wenn die Richtlinie mit demselben Ursprung den Zugriff auf zulässt parent.location. Andernfalls wird eine Ausnahme ausgelöst
Dan
-1

Wenn Sie wissen möchten, ob der Benutzer über die Registerkarte "Facebook-Seite" oder "Canvas" auf Ihre App zugreift, suchen Sie nach der signierten Anforderung. Wenn Sie es nicht bekommen, greift der Benutzer wahrscheinlich nicht über Facebook zu. Um sicherzustellen, bestätigen Sie die Struktur der signierten_Anforderungsfelder und den Inhalt der Felder.

Mit dem php-sdk können Sie die signierte Anfrage wie folgt erhalten:

$signed_request = $facebook->getSignedRequest();

Weitere Informationen zu Signed Request finden Sie hier:

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

und hier:

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

Joao Belchior
quelle
-1

Dies war für mich die einfachste Lösung.

    <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>
Alex Roseland
quelle
-4
if (window.frames.length != parent.frames.length) { page loaded in iframe }

Aber nur, wenn sich die Anzahl der Iframes auf Ihrer Seite und der Seite, die Sie in Iframe laden, unterscheidet. Machen Sie keinen Iframe auf Ihrer Seite, um eine 100% ige Garantie für das Ergebnis dieses Codes zu erhalten

Vova Popov
quelle
Keine sehr elegante Lösung, um festzustellen, ob sich das Fenster in einem Iframe befindet oder nicht, und es gibt keine Garantie dafür, dass Sie auch aus parent.frames lesen können.
Percy
-4

Schreiben Sie dieses Javascript auf jede Seite

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

Dann wird automatisch zur Startseite weitergeleitet.

Shibin
quelle
4
Ihre Umleitung funktioniert, wenn Sie kein Frame sind. Ich könnte also nicht auf Ihrer Website navigieren. Zweitens gibt es Techniken, um zu verhindern, dass von der übergeordneten Seite umgeleitet wird.
Marius Balčytis