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

597

Estou escrevendo um aplicativo de facebook baseado em iframe. Agora, quero usar a mesma página html para renderizar o site normal e a página de tela no facebook. Quero saber se posso determinar se a página foi carregada dentro do iframe ou diretamente no navegador?

akshat
fonte
2
Algumas maneiras legais (incluindo comentários): tommcfarlin.com/check-if-a-page-is-in-an-iframe
simhumileco

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.

Greg
fonte
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.

Konstantin Smolyanin
fonte
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.

scunliffe
fonte
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.

magnoz
fonte
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;
portal TheAnGeLs
fonte
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);
mikewolf78
fonte
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;
}
Rolf
fonte
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

Albert Olivé
fonte
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   
}
William
fonte
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.

HectorMac
fonte
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;
Jabran Saeed
fonte
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';
}
Erro601
fonte
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/

Joao Belchior
fonte
-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>
Alex Roseland
fonte
-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

Vova Popov
fonte
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.

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