Come identificare se una pagina Web viene caricata all'interno di un iframe o direttamente nella finestra del browser?


597

Sto scrivendo un'app Facebook basata su iframe. Ora voglio usare la stessa pagina HTML per il rendering del normale sito Web e della pagina tela all'interno di Facebook. Voglio sapere se posso determinare se la pagina è stata caricata all'interno dell'iframe o direttamente nel browser?


2
Alcuni bei modi (inclusi i commenti): tommcfarlin.com/check-if-a-page-is-in-an-iframe
simhumileco

Risposte:


1108

I browser possono bloccare l'accesso a window.topcausa della stessa politica di origine . Si verificano anche bug di IE. Ecco il codice di lavoro:

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

tope selfsono entrambi windowoggetti (insieme a parent), quindi vedrai se la tua finestra è la finestra in alto.


4
Questo sembra funzionare bene in Firefox. Funziona anche con altri browser?
akshat il

5
Avere una pagina con un iframe all'interno di un iframe, per verificare da mio figlio iframe se il mio genitore iframe fosse incorporato nella pagina, ho usato if (parent === top)
sglessard

7
@sglessard Se la pagina figlio e il genitore provengono da domini diversi, Firefox si lamenterà della stessa politica sull'origine (www.w3.org/Security/wiki/Same_Origin_Policy) e il codice non funzionerà
Gaurang Jadia

18
Questo funziona in IE 11, 10 e 9 per me. Funziona anche in FF e Opera e, ovviamente, Chrome. Non ho riscontrato alcun problema.
jeremysawesome

4
Per coloro che continuano a scuotere l'ultima tecnologia del 1995, window.self !== window.topritorna truequando viene eseguito all'interno dei contenuti di frame, o iframe .
Jeromy francese

84

Quando si trova in un iframe sulla stessa origine del genitore, il window.frameElementmetodo restituisce l'elemento (ad esempio iframeo object) in cui è incorporata la finestra. Altrimenti, se la navigazione in un contesto di livello superiore o se il frame principale e secondario hanno origini diverse, verrà valutato null.

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

Questo è uno standard HTML con supporto di base in tutti i browser moderni.


2
Nota che il tentativo di leggere frameElementgenererà un'eccezione SecurityError negli iframe tra origini, secondo W3C ( WHATWG dice che dovrebbe invece restituire null). Quindi potresti voler racchiuderlo in una try...catchdichiarazione.
Oriol

5
entrare nulle uscire daiframe
OlehZiniak il

4
La descrizione in MDN dice che "se il documento in cui è incorporato ha un'origine diversa (come se fosse stato trovato da un dominio diverso), questo è nullo".
Xeophin

Giusto per chiarire quale dovrebbe essere il ritorno: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 è corretto, ma volevo aggiungere una nota a margine.

In IE7 / IE8 quando Microsoft ha aggiunto Tab al loro browser hanno rotto una cosa che causerà il caos con il tuo JS se non stai attento.

Immagina questo layout di pagina:

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

Ora nel frame "baz" fai clic su un link (nessun target, carica nel frame "baz") funziona bene.

Se la pagina che viene caricata, chiamiamola special.html, usa JS per verificare se "esso" ha un frame principale chiamato "bar", restituirà vero (previsto).

Ora supponiamo che la pagina special.html quando viene caricata, controlla il frame principale (per l'esistenza e il suo nome, e se è "bar" si ricarica nel frame bar. Es.

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

Fin qui tutto bene. Ora arriva il bug.

Diciamo invece di fare clic sul collegamento originale come al solito, e caricando la pagina special.html nel frame "baz", hai fatto clic con il pulsante centrale o hai scelto di aprirlo in una nuova scheda.

Quando quella nuova scheda viene caricata ( senza frame principali! ) IE entrerà in un ciclo infinito di caricamento della pagina! perché IE "copia" la struttura del frame in JavaScript in modo tale che la nuova scheda abbia un padre e che il padre abbia il nome "barra".

La buona notizia è che controllando:

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

in quella nuova scheda ritorna vero, e quindi puoi provare questa strana condizione.


Nel frattempo il bug è stato corretto? Non riesco a riprodurlo in IE8. Ottengo sempre il corretto window.parent.
user123444555621

1
Non sono sicuro: eseguirò la mia suite di test su IE9 e di seguito e pubblicherò un aggiornamento.
scunliffe,

18

La risposta accettata non ha funzionato per me all'interno dello script di contenuto di un'estensione di Firefox 6.0 (Addon-SDK 1.0): Firefox esegue lo script di contenuto in ciascuno: la finestra di livello superiore e in tutti gli iframe.

All'interno dello script del contenuto ottengo i seguenti risultati:

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

La cosa strana di questo output è che è sempre lo stesso indipendentemente dal fatto che il codice sia eseguito all'interno di un iframe o nella finestra di livello superiore.

D'altra parte, Google Chrome sembra eseguire il mio script dei contenuti solo una volta all'interno della finestra di livello superiore, quindi quanto sopra non funzionerebbe affatto.

Ciò che alla fine ha funzionato per me in uno script di contenuto in entrambi i browser è questo:

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

Senza iframe questo viene stampato 0:0, in una finestra di livello superiore contenente un frame che stampa 1:1e nell'unico iframe di un documento che stampa 0:1.

Ciò consente alla mia estensione di determinare in entrambi i browser se sono presenti iframe e, inoltre, in Firefox se viene eseguito all'interno di uno degli iframe.


1
Prova document.defaultView.self === document.defaultView.topo window !== window.top. Nello script del contenuto aggiuntivo SDK di Firefox, l' selfoggetto globale è un oggetto utilizzato per comunicare con lo script principale.
Rob W

13

Non sono sicuro di come questo esempio funzioni per i browser Web meno recenti, ma lo uso per IE, Firefox e Chrome senza problemi:

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

6
O semplicemente!(window===window.parent)
CalculatorFeline

11
window! == window.parent
Ivan Leonenko il

5

Sto usando questo:

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

Perché lo fai .indexOf("HTMLIFrameElement"):?
Luca,

.indexOf ('foobarbaz')> -1 è un modo per verificare la "corrispondenza della sottostringa" (cioè 'foobarbaz' può essere trovato da qualche parte all'interno della stringa?), ma senza usare espressioni regolari. È logicamente equivalente a .match (/ foobarbaz /). (Utilizzato per :-) funziona su una gamma più ampia di browser e può ancora essere utilizzato per abitudine o per timori riguardo alle prestazioni dei macchinari per le espressioni regolari.
Chuck Kollars,

2

Utilizzare questa funzione JavaScript come esempio su come eseguire questa operazione.

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

Best-for-now Legacy Browser Frame Breaking Script

Le altre soluzioni non hanno funzionato per me. Questo funziona su tutti i browser:

Un modo per difendersi dal clickjacking è includere uno script "frame-breaker" in ogni pagina che non dovrebbe essere inquadrato. La seguente metodologia eviterà che una pagina web venga inquadrata anche nei browser legacy, che non supportano X-Frame-Options-Header.

Nell'elemento HEAD del documento, aggiungere quanto segue:

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

Innanzitutto applica un ID all'elemento di stile stesso:

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

In questo modo, tutto può essere contenuto nel documento HEAD e nell'API è necessario solo un metodo / taglib.

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


1
l'inquadramento non è l'unica minaccia, che dire dell'obiezione (che significa usare il tag oggetto HTML5 che sostituisce il tag iframe) .. penso che questo non funzionerà contro quello ..
Raymond Nijland,

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

1

Dato che stai chiedendo nel contesto di un'app di Facebook, potresti prendere in considerazione l'idea di rilevarlo sul server quando viene effettuata la richiesta iniziale. Facebook passerà un mucchio di dati di querystring tra cui il tasto fb_sig_user se viene chiamato da un iframe.

Poiché probabilmente è necessario controllare e utilizzare questi dati comunque nella propria app, utilizzarli per determinare il contesto appropriato per il rendering.


1

In realtà controllavo window.parent e ha funzionato per me, ma ultimamente window è un oggetto ciclico e ha sempre una chiave genitore, iframe o no iframe.

Come i commenti suggeriscono un duro confronto con i lavori di window.parent. Non sono sicuro che funzionerà se iframe è esattamente la stessa pagina web del genitore.

window === window.parent;

in Chrome nel contesto della finestra principale window.parent === windowè vero. Quindi la tua risposta non è corretta. E questa comparazione potrebbe essere usata per il controllo (almeno in Chrome, non è stato testato in altri browser).
MarkosyanArtur,

NON FUNZIONA nel contesto di iFrame, ma `if (window === window.parent) {` funziona. Non ti
segnerò

-1

È un antico pezzo di codice che ho usato alcune volte:

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

Per aggiungere a Eneko Alonso: funziona(parent.location == self.location)
piotr_cz

@piotr_cz, funziona solo se la politica della stessa origine consente l'accesso parent.location. Altrimenti viene generata un'eccezione
Dan,

-1

Se vuoi sapere se l'utente sta accedendo alla tua app dalla scheda della pagina Facebook o dalla tela, controlla la richiesta firmata. Se non lo capisci, probabilmente l'utente non accede da Facebook. Per essere sicuri di confermare la struttura dei campi signed_request e il contenuto dei campi.

Con php-sdk puoi ottenere la richiesta firmata in questo modo:

$signed_request = $facebook->getSignedRequest();

Puoi leggere ulteriori informazioni sulla richiesta firmata qui:

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

e qui:

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


-1

Questa è stata la soluzione più semplice per me.

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

Ma solo se il numero di iframe differisce nella tua pagina e pagina che ti sta caricando in iframe. Non creare iframe nella tua pagina per avere il 100% di garanzia sul risultato di questo codice


Non è una soluzione molto elegante per determinare se la finestra si trova all'interno di un iframe o meno, e non vi è alcuna garanzia che sarai in grado di leggere anche da parent.frames.
Percy,

-4

Scrivi questo javascript in ogni pagina

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

Quindi reindirizzerà automaticamente alla home page.


4
Il reindirizzamento funzionerà quando non lo sei se frame. Quindi non sarei in grado di navigare nel tuo sito. In secondo luogo, esistono tecniche per impedire il reindirizzamento dalla pagina principale.
Marius Balčytis
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.