Como identificar se uma página da Web está sendo carregada dentro de um iframe ou diretamente na janela do navegador?


Respostas:


1108

Os navegadores podem bloquear o acesso window.topdevido à mesma política de origem . Os erros do IE também ocorrem. Aqui está o código de trabalho:

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

tope selfsão ambos windowobjetos (junto com parent), para ver se sua janela é a janela superior.


4
Isso parece funcionar bem no Firefox. Também funciona em outros navegadores?
Akshat

5
Ter uma página com um iframe dentro de um iframe, para teste do meu iframe criança se meu iframe pai foi embeded na página, eu costumava se (pai === superior)
sglessard

7
@sglessard Se a página criança e os pais são de diferentes domínios, em seguida, o Firefox irá reclamar para a Política de mesma origem (www.w3.org/Security/wiki/Same_Origin_Policy) eo código não vai funcionar
Gaurang Jadia

18
Isso funciona no IE 11, 10 e 9 para mim. Também funciona em FF e Opera, bem como, é claro, no Chrome. Não tenho problemas com isso.
precisa saber é o seguinte

4
Para aqueles que ainda estão usando a mais recente tecnologia de 1995, window.self !== window.topretornam truequando executados a partir do conteúdo de frame, ou iframe .
Jeromy French 23/03

84

Quando em um iframe na mesma origem que o pai, o window.frameElementmétodo retorna o elemento (por exemplo, iframeou object) no qual a janela está incorporada. Caso contrário, se estiver navegando em um contexto de nível superior, ou se o quadro pai e o filho tiverem origens diferentes, será avaliado como null.

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

Este é um padrão HTML com suporte básico em todos os navegadores modernos.


2
A tentativa de leitura frameElementlançará uma exceção SecurityError em iframes de origem cruzada, de acordo com o W3C (o WHATWG diz que deve retornar nulo). Portanto, você pode querer envolvê-lo em uma try...catchdeclaração.
Oriol

5
ficando nulldentro e foraiframe
OlehZiniak

4
A descrição no MDN diz que "se o documento no qual está incorporado tiver uma origem diferente (como ter sido localizado em um domínio diferente), isso será nulo".
xeophin

Só para clerify o que o retorno deve ser: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

O RoBorg está correto, mas eu queria adicionar uma nota lateral.

No IE7 / IE8, quando a Microsoft adicionou Guias ao navegador, eles quebraram uma coisa que causaria estragos no seu JS se você não tomar cuidado.

Imagine este layout de página:

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

Agora, no quadro "baz", você clica em um link (sem destino, carrega no quadro "baz") que funciona bem.

Se a página carregada, vamos chamá-la special.html, usa JS para verificar se "it" possui um quadro pai chamado "bar" e retornará true (esperado).

Agora, digamos que a página special.html, quando carregada, verifica o quadro pai (quanto à existência e seu nome, e se for "bar", ele se recarrega no quadro de barras.

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

Por enquanto, tudo bem. Agora vem o bug.

Digamos que, em vez de clicar no link original como de costume, e carregando a página special.html no quadro "baz", você clicou no meio ou optou por abri-la em uma nova guia.

Quando essa nova guia for carregada ( sem quadros-pai! ), O IE entrará em um loop infinito de carregamento de página!porque o IE "copia" a estrutura do quadro em JavaScript, de modo que a nova guia tenha um pai e esse pai tenha o nome "barra".

A boa notícia é que verificando:

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

nessa nova guia retorna true e, portanto, você pode testar esta condição ímpar.


O bug foi corrigido enquanto isso? Não consigo reproduzi-lo no IE8. Eu sempre entendo o correto window.parent.
user123444555621

1
Não tenho certeza - executarei minha suíte de testes no IE9 e abaixo novamente e publicarei uma atualização.
scunliffe

18

A resposta aceita não funcionou para mim dentro do script de conteúdo de uma extensão do Firefox 6.0 (Addon-SDK 1.0): o Firefox executa o script de conteúdo em cada um: na janela de nível superior e em todos os iframes.

Dentro do script de conteúdo, obtenho os seguintes resultados:

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

O estranho dessa saída é que é sempre a mesma, independentemente de o código ser executado dentro de um iframe ou na janela de nível superior.

Por outro lado, o Google Chrome parece executar meu script de conteúdo apenas uma vez na janela de nível superior, para que o procedimento acima não funcione.

O que finalmente funcionou para mim em um script de conteúdo nos dois navegadores é o seguinte:

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

Sem iframes, isso é impresso 0:0, em uma janela de nível superior que contém um quadro impresso 1:1e no único iframe de um documento impresso 0:1.

Isso permite que minha extensão determine nos dois navegadores se há iframes presentes e, adicionalmente, no Firefox se for executada dentro de um dos iframes.


1
Tente document.defaultView.self === document.defaultView.topou window !== window.top. No script de conteúdo do SDK de expansão do Firefox, o selfobjeto global é um objeto usado para se comunicar com o script principal.
Rob

13

Não tenho certeza de como este exemplo funciona para navegadores da Web mais antigos, mas eu o uso para o IE, Firefox e Chrome sem um problema:

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

6
Ou simplesmente!(window===window.parent)
CalculatorFeline

11
window! == window.parent
Ivan Leonenko

5

Eu estou usando isso:

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

Por que você faz isso .indexOf("HTMLIFrameElement"):?
Luke

.indexOf ('foobarbaz')> -1 é uma maneira de verificar a "correspondência de substring" (ou seja, 'foobarbaz' pode ser encontrado em algum lugar da string?), mas sem o uso de expressões regulares. É logicamente equivalente a .match (/ foobarbaz /). (Costumava :-) trabalhar em uma variedade maior de navegadores, e ainda pode ser usado por hábito ou por temores sobre o desempenho de máquinas de expressão regular.
Chuck Kollars

2

Use esta função javascript como um exemplo de como fazer isso.

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

Script de quebra de quadro do navegador herdado, o melhor por agora

As outras soluções não funcionaram para mim. Este funciona em todos os navegadores:

Uma maneira de se defender contra o clickjacking é incluir um script de "quebra de quadros" em cada página que não deve ser enquadrada. A metodologia a seguir impedirá que uma página da Web seja enquadrada mesmo em navegadores herdados, que não suportam o X-Frame-Options-Header.

No elemento HEAD do documento, adicione o seguinte:

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

Primeiro, aplique um ID ao próprio elemento de estilo:

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

Dessa forma, tudo pode estar no documento HEAD e você só precisa de um método / taglib na sua API.

Referência: https://www.codemagi.com/blog/post/194


1
enquadramento não é a única ameaça, que tal objeção (ou seja, usando a tag HTML5 objeto que substitui iframe tag) .. eu acho que isso não vai funcionar contra isso ..
Raymond Nijland

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

1

Como você está perguntando no contexto de um aplicativo do facebook, considere detectar isso no servidor quando a solicitação inicial é feita. O Facebook transmitirá um monte de dados da string de consulta, incluindo a chave fb_sig_user, se for chamada de um iframe.

Como você provavelmente precisa verificar e usar esses dados de qualquer maneira no seu aplicativo, use-os para determinar o contexto apropriado a ser renderizado.


1

Na verdade, eu costumava verificar o window.parent e funcionou para mim, mas ultimamente o window é um objeto cíclico e sempre possui uma chave pai, iframe ou iframe.

Como os comentários sugerem, é difícil comparar com os trabalhos window.parent. Não tenho certeza se isso funcionará se o iframe for exatamente a mesma página da Web como pai.

window === window.parent;

no chrome no contexto da janela principal window.parent === windowé verdadeiro. Portanto, sua resposta está incorreta. E essa comparação poderia ser usada para verificação (pelo menos no chrome, não foi testada em outros navegadores).
precisa saber é o seguinte

NÃO FUNCIONA no contexto do iFrame, mas `if (window === window.parent) {` funciona. Eu não estou marcando você como eu não sei por que não funciona #
-0av-Com

-1

É um antigo código que eu usei algumas vezes:

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

Para adicionar Eneko Alonso: isso funciona(parent.location == self.location)
piotr_cz

@piotr_cz, funciona apenas se a política de mesma origem permitir acesso parent.location. Caso contrário, uma exceção é lançada
Dan

-1

Se você deseja saber se o usuário está acessando seu aplicativo na guia da página do Facebook ou na tela, verifique a Solicitação assinada. Se você não conseguir, provavelmente o usuário não está acessando no facebook. Para certificar-se de confirmar a estrutura dos campos de assinatura_request e o conteúdo dos campos.

Com o php-sdk, você pode obter a solicitação assinada como esta:

$signed_request = $facebook->getSignedRequest();

Você pode ler mais sobre Solicitação assinada aqui:

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

e aqui:

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


-1

Isso acabou sendo a solução mais simples para mim.

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

Mas apenas se o número de iframes for diferente na sua página e na página que está carregando você no iframe. Não crie iframe na sua página para ter 100% de garantia do resultado desse código


Não é uma solução muito elegante para determinar se a janela está ou não dentro de um iframe ou não, e não há garantia de que você será capaz de ler em parent.frames também.
Percy

-4

Escreva esse javascript em cada página

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

Em seguida, ele será redirecionado automaticamente para a página inicial.


4
Seu redirecionamento funcionará quando você não estiver se enquadrar. Portanto, eu não seria capaz de navegar no seu site. Em segundo lugar, existem técnicas para impedir o redirecionamento da página pai.
Marius Balčytis
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.