Comment identifier si une page Web est chargée dans une iframe ou directement dans la fenêtre du navigateur?

598

J'écris une application facebook basée sur iframe. Maintenant, je veux utiliser la même page html pour rendre le site Web normal ainsi que la page de toile dans Facebook. Je veux savoir si je peux déterminer si la page a été chargée dans l'iframe ou directement dans le navigateur?

akshat
la source
2
Quelques bonnes façons (y compris les commentaires): tommcfarlin.com/check-if-a-page-is-in-an-iframe
simhumileco

Réponses:

1109

Les navigateurs peuvent bloquer l'accès en window.topraison de la même politique d'origine . Des bogues IE ont également lieu. Voici le code de travail:

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

topet selfsont les deux windowobjets (avec parent), vous voyez donc si votre fenêtre est la fenêtre supérieure.

Greg
la source
4
Cela semble bien fonctionner dans Firefox. Cela fonctionne-t-il également dans d'autres navigateurs?
akshat
5
Avoir une page avec un iframe dans un iframe, pour tester depuis mon enfant iframe si mon parent iframe a été intégré dans la page, j'ai utilisé if (parent === top)
sglessard
7
@sglessard Si la page enfant et le parent proviennent de domaines différents, Firefox se plaindra de la même politique d'origine (www.w3.org/Security/wiki/Same_Origin_Policy) et le code ne fonctionnera pas
Gaurang Jadia
18
Cela fonctionne pour IE 11, 10 et 9 pour moi. Il fonctionne également dans FF et Opera ainsi que, bien sûr, dans Chrome. Je n'ai rencontré aucun problème avec cela.
jeremysawesome
4
Pour ceux qui utilisent encore la dernière technologie de 1995, window.self !== window.toprevient truequand il est exécuté à partir du contenu de frame, ou iframe .
Jeromy French
84

Lorsqu'elle se trouve dans une iframe de la même origine que le parent, la window.frameElementméthode renvoie l'élément (par exemple, iframeou object) dans lequel la fenêtre est incorporée. Sinon, si la navigation dans un contexte de niveau supérieur, ou si le parent et le cadre enfant ont des origines différentes, il sera évalué null.

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

Il s'agit d'une norme HTML avec une prise en charge de base dans tous les navigateurs modernes.

Konstantin Smolyanin
la source
2
Remarque: une tentative de lecture frameElementlèvera une exception SecurityError dans les iframes d'origine croisée, selon W3C ( WHATWG dit qu'il devrait retourner null à la place). Vous voudrez donc peut-être l'envelopper dans une try...catchdéclaration.
Oriol
5
entrer nullet sortir deiframe
OlehZiniak
4
La description de MDN indique que "si le document dans lequel il est incorporé a une origine différente (comme avoir été localisé à partir d'un domaine différent), cela est nul".
xeophin
Juste pour vérifier ce que devrait être le retour: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 est correct, mais je voulais ajouter une note latérale.

Dans IE7 / IE8, lorsque Microsoft a ajouté des onglets à son navigateur, il a cassé une chose qui causera des ravages avec votre JS si vous ne faites pas attention.

Imaginez cette mise en page:

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

Maintenant, dans le cadre "baz", vous cliquez sur un lien (pas de cible, se charge dans le cadre "baz"), cela fonctionne bien.

Si la page qui est chargée, appelons-la special.html, utilise JS pour vérifier si "it" a un cadre parent nommé "bar", il retournera true (attendu).

Disons maintenant que la page special.html lors de son chargement, vérifie le cadre parent (pour l'existence et son nom, et s'il s'agit de "bar", elle se recharge dans le cadre de la barre. Ex.

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

Jusqu'ici tout va bien. Maintenant vient le bug.

Disons qu'au lieu de cliquer sur le lien d'origine comme d'habitude, et de charger la page special.html dans le cadre "baz", vous avez cliqué avec le bouton du milieu ou choisi de l'ouvrir dans un nouvel onglet.

Lorsque ce nouvel onglet se charge ( sans aucun cadre parent! ), IE entrera dans une boucle sans fin de chargement de page! car IE "copie" la structure du cadre en JavaScript de telle sorte que le nouvel onglet A un parent et que ce parent A le nom "bar".

La bonne nouvelle, c'est que la vérification:

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

dans ce nouvel onglet retourne vrai, et donc vous pouvez tester cette condition étrange.

scunliffe
la source
Le bug a-t-il été corrigé entre-temps? Je ne peux pas le reproduire dans IE8. J'ai toujours le bon window.parent.
user123444555621
1
Pas sûr - je lancerai à nouveau ma suite de tests contre IE9 et ci-dessous et publierai une mise à jour.
scunliffe
18

La réponse acceptée n'a pas fonctionné pour moi dans le script de contenu d'une extension Firefox 6.0 (Addon-SDK 1.0): Firefox exécute le script de contenu dans chacun: la fenêtre de niveau supérieur et dans tous les iframes.

Dans le script de contenu, j'obtiens les résultats suivants:

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

La chose étrange à propos de cette sortie est qu'elle est toujours la même, que le code soit exécuté à l'intérieur d'une iframe ou de la fenêtre de niveau supérieur.

D'un autre côté, Google Chrome semble exécuter mon script de contenu une seule fois dans la fenêtre de niveau supérieur, de sorte que ce qui précède ne fonctionnerait pas du tout.

Ce qui a finalement fonctionné pour moi dans un script de contenu dans les deux navigateurs est le suivant:

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

Sans iframes, cela s'imprime 0:0, dans une fenêtre de niveau supérieur contenant un cadre qu'il imprime 1:1et dans la seule iframe d'un document qu'il imprime 0:1.

Cela permet à mon extension de déterminer dans les deux navigateurs s'il y a des iframes présents, et en plus dans Firefox si elle est exécutée dans l'un des iframes.

magnoz
la source
1
Essayez document.defaultView.self === document.defaultView.topou window !== window.top. Dans le script de contenu du module complémentaire SDK de Firefox, l' selfobjet global est un objet utilisé pour communiquer avec le script principal.
Rob W
13

Je ne sais pas comment cet exemple fonctionne pour les anciens navigateurs Web, mais je l'utilise pour IE, Firefox et Chrome sans et problème:

var iFrameDetection = (window === window.parent) ? false : true;
portail TheAnGeLs
la source
6
Ou tout simplement!(window===window.parent)
CalculatorFeline
11
window! == window.parent
Ivan Leonenko
5

J'utilise ceci:

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);
mikewolf78
la source
Pourquoi faites-vous cela .indexOf("HTMLIFrameElement"):?
Luke
.indexOf ('foobarbaz')> -1 est un moyen de vérifier la "correspondance de sous-chaîne" (c'est-à-dire que 'foobarbaz' peut être trouvé quelque part dans la chaîne?), mais sans utiliser d'expressions régulières. Il est logiquement équivalent à .match (/ foobarbaz /). Il (utilisé pour :-) fonctionne sur une plus large gamme de navigateurs et peut toujours être utilisé par habitude ou en raison de craintes concernant les performances des machines d'expression régulière.
Chuck Kollars
2

Utilisez cette fonction javascript comme exemple sur la façon d'accomplir cela.

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
la source
2

Meilleur script de rupture de trame de navigateur hérité

Les autres solutions n'ont pas fonctionné pour moi. Celui-ci fonctionne sur tous les navigateurs:

Une façon de se défendre contre le détournement de clics consiste à inclure un script "frame-breaker" dans chaque page qui ne doit pas être encadrée. La méthodologie suivante empêchera une page Web d'être encadrée même dans les navigateurs hérités, qui ne prennent pas en charge l'en-tête X-Frame-Options.

Dans l'élément HEAD du document, ajoutez ce qui suit:

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

Appliquez d'abord un ID à l'élément de style lui-même:

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

De cette façon, tout peut être dans le document HEAD et vous n'avez besoin que d'une méthode / taglib dans votre API.

Référence: https://www.codemagi.com/blog/post/194

Albert Olivé
la source
1
le cadrage n'est pas la seule menace, qu'en est-il de l'objection (ce qui signifie utiliser la balise d'objet HTML5 qui remplace la balise iframe) .. je pense que cela ne fonctionnera pas contre cela ..
Raymond Nijland
2
if ( window.location !== window.parent.location ) 
{
      // The page is in an iframe   
} 
else 
{     
      // The page is not in an iframe   
}
William
la source
1

Puisque vous posez la question dans le contexte d'une application Facebook, vous voudrez peut-être envisager de détecter cela sur le serveur lors de la demande initiale. Facebook transmettra un tas de données de chaîne de requête, y compris la clé fb_sig_user si elle est appelée à partir d'un iframe.

Étant donné que vous devez probablement vérifier et utiliser ces données de toute façon dans votre application, utilisez-les pour déterminer le contexte approprié à rendre.

HectorMac
la source
1

En fait, je vérifiais window.parent et cela a fonctionné pour moi, mais dernièrement, window est un objet cyclique et a toujours une clé parent, iframe ou no iframe.

Comme les commentaires suggèrent une comparaison difficile avec les travaux de window.parent. Je ne sais pas si cela fonctionnera si iframe est exactement la même page Web que le parent.

window === window.parent;
Jabran Saeed
la source
en chrome dans le contexte de la fenêtre principale window.parent === windowest vrai. Votre réponse est donc incorrecte. Et cette comparaison pourrait être utilisée pour la vérification (au moins dans Chrome, ne l'a pas testée dans d'autres navigateurs).
MarkosyanArtur
NE FONCTIONNE PAS dans le contexte d'iFrame, mais `if (window === window.parent) {` le fait. Je ne vous
note
-1

C'est un ancien morceau de code que j'ai utilisé plusieurs fois:

if (parent.location.href == self.location.href) {
    window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}
Erreur601
la source
Pour ajouter à Eneko Alonso: cela fonctionne(parent.location == self.location)
piotr_cz
@piotr_cz, cela ne fonctionne que si la politique de même origine autorise l'accès à parent.location. Sinon, une exception est levée
Dan
-1

Si vous voulez savoir si l'utilisateur accède à votre application à partir de l'onglet de la page Facebook ou de la toile, vérifiez la demande signée. Si vous ne l'obtenez pas, l'utilisateur n'a probablement pas accès à partir de Facebook. Pour vous assurer de confirmer la structure et le contenu des champs signed_request.

Avec le php-sdk, vous pouvez obtenir la demande signée comme ceci:

$signed_request = $facebook->getSignedRequest();

Vous pouvez en savoir plus sur la demande signée ici:

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

et ici:

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

Joao Belchior
la source
-1

Cela a fini par être la solution la plus simple pour moi.

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

Mais seulement si le nombre d'iframes diffère dans votre page et la page qui vous charge dans iframe. Ne faites pas d'iframe dans votre page pour avoir une garantie à 100% du résultat de ce code

Vova Popov
la source
Ce n'est pas une solution très élégante pour déterminer si la fenêtre se trouve dans une iframe ou non, et il n'y a aucune garantie que vous pourrez lire à partir de parent.frames.
Percy
-4

Écrivez ce javascript dans chaque page

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

Ensuite, il sera automatiquement redirigé vers la page d'accueil.

shibin
la source
4
Votre redirection fonctionnera lorsque vous n'êtes pas si le cadre. Je ne pourrais donc pas naviguer sur votre site. Deuxièmement, des techniques existent pour empêcher la redirection depuis la page parent.
Marius Balčytis