Foolproof way to detect if this page is INSIDE a c

2019-01-14 11:30发布

问题:

An answer to "Foolproof way to detect if iframe is cross domain" describes a method to test if an iframe on a page points to a same-domain or cross-domain page, working around different browsers' interpretations of the cross-domain policy and avoiding error messages that would interrupt a user or stop javascript.

I'm looking to do the equivalent of this but from the child page inside the iframe testing whether it is inside a cross-domain iframe or not.

It's possible to access (same domain) info about the parent with the parent global e.g. parent.document.location, but is there a reliable way to do this cross-browser without crashing into errors when it detects that the parent is cross-domain?


For handy testing, here's a jsbin inside a jsfiddle that crashes into an error when trying to test if parent.location.host is accessible. Is there a reliable way to get something usable like false telling us that this is a cross-domain parent, instead of an error?

Is there a try...catch variant which will be robust cross-browser? Or maybe some clever trick using a return value from parent.postMessage()? (although the parent page cannot be edited)


Use case: imagine embedable content that is to be embedded on pages on its own site, and by third parties. If the page is on a same-domain iframe, we hide branding and links back to the original site because the user is already here. If they access the page from a 3rd party iframe or load the page directly, we show the branding and credits so they can see the source of the content.


To clarify, I know about the same-domain policy and I don't care what the cross browser domain is, I'm just looking to write a simple but reliable if condition like if( crossDomainParent() ){ /* do something */}

回答1:

First check if you are IFramed.

window.self !== window.top

If you are IFramed, then your referrer is your parent frame url.

document.referrer

From this url you should be able to detect if you want to branch your code.



回答2:

Real cross-browser solution for posterity:

function isCrossOriginFrame() {
  try {
    return (!window.top.location.hostname);
  } catch (e) {
    return true;
  }
}

console.log(isCrossOriginFrame());

Tested on a decent swath of desktop and mobile browsers.

https://jsfiddle.net/arzd4btc/3/



回答3:

use x-frame header this will prevent to load your site to frame/iframe . there are various options read here



回答4:

With your current restrictions, there's no way to achieve this using the DOM API. Any evaluation with a window that belongs to another domain will spew out an error.

However, a "hack" would be to send an XHR from your child window to load a known page in your domain. If this XHR completes successfully, then you know that both windows are the same domain.

However, this will log an error message to the console.



回答5:

Try this (in iframe)

<script type="text/javascript">
  var detectOrigin = (window.location.ancestorOrigins === undefined ? 
  /example.com/.test(document.domain) /* firefox */ : 
  /example.com/.test(window.location.ancestorOrigins[0])); /* webkit */
  if (detectOrigin === true) {console.log(detectOrigin)}; /* `true` example.com origin */
  if (detectOrigin === false) {console.log(detectOrigin)}; /* `false` !example.com origin */
</script>


回答6:

If I see your use case:

I would check it server side (who called your site), using $_SERVER['REMOTE_ADDR'], and if it is your IP than you can hide branding and links backs.

If the use case is about to prevent framing your site you can use X-Frame-Options: deny.

Other guess: Elements inside a document have a ownerDocument property, maybe that can help detecting what you want.



回答7:

I attempted to use referer to determine cross-domain, but I discovered it was unreliable on many sites. Maybe someone will find this useful.

function IsCrossDomainFrame() {
    if( parent === window ) return false; //not a frame
    var parentLocation = new URL(document.referer);//the referer of an iframe is the parent
    return (parentLocation.protocol !== location.protocol ||
            parentLocation.hostname !== location.hostname ||
            parentLocation.port     !== location.port);
}

Protocol, hostname, and port determine cross-domain.



回答8:

For nested iframes : a recursive way to know if iframe (where this code is executed) is cross domain or not :

function crosDomIfrm(win, data) {
        data = (typeof data === 'undefined')?{ref:win.document.location,isCD:false}:data;
        try { 
            if( win.document.referrer != '' ){
                data.isCD = parseURL(data.ref) != parseURL(win.document.referrer);
            }
        } catch(e){}
        if ( (win.self !== win.parent) && !data.isCD ) { //I'm in iframe
            data = crosDomIfrm( win.parent, data );
        }
        return {ref:data.ref,isCD:data.isCD};
    },

function parseURL(url) {
                var a=document.createElement('a');
                a.href=url;
                return a.hostname;
            }