Foolproof way to detect if this page is INSIDE a cross-domain iframe

23,701

Solution 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.

Solution 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/

Solution 3

I attempted to use referrer 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.referrer);//the referrer 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.

Solution 4

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

Solution 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>
Share:
23,701
user56reinstatemonica8
Author by

user56reinstatemonica8

See: https://meta.stackexchange.com/q/336526/178621

Updated on January 19, 2022

Comments

  • user56reinstatemonica8
    user56reinstatemonica8 over 2 years

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

  • user56reinstatemonica8
    user56reinstatemonica8 about 10 years
    Interesting idea, +1. I've only done a little cross-browser testing so far, but based on that it does indeed look like you can safely check document.referrer, first checking it's not an empty string (which it will be if it's not framed in Firefox) then parsing it to get the domain. Can't test IE right now, will try later. Using jsfiddle.net/Ke3Z6/4 and jsbin.com/loyuy/10/edit
  • mikesjawnbit
    mikesjawnbit about 10 years
    document.referrer only works if the framed page has not navigated anywhere! As soon as this happens, referrer becomes previous framed page.
  • user56reinstatemonica8
    user56reinstatemonica8 over 9 years
    Good point - luckily the framed content is content you have control over, so it may be possible to make sure the page doesn't navigate.
  • Craig Kovatch
    Craig Kovatch over 7 years
    window.top throws the uncatchable security error in Chrome.
  • Maxime Rossini
    Maxime Rossini over 7 years
    The referrer is not a reliable value, it can be deactivated, forged, and in some cases not being sent by requirement, such as when the referrer is HTTPS and the target HTTP. It should work for your use case thought, but I wouldn't be too confident about it. One proper way to do this would be to manage 2 URL, one without branding but returning the HTTP header X-FrameOptions as SAMEORIGIN, the other with branding and without this header.
  • N-ate
    N-ate over 6 years
    working on a script for instacart.com. None of the iframes have referers.
  • N-ate
    N-ate over 6 years
    The problem in chrome can be overcome by checking if parent === window. This of course would fail to be an accurate check in a popup.
  • Jonathan Harris
    Jonathan Harris about 5 years
    Thx @JeffMixon, I changed this slightly, to this: function isCrossOriginFrame() { try { return (document.location.hostname !== window.parent.location.hostname); } catch (e) { return true; } }
  • Benny K
    Benny K over 3 years
    This will make a browser display an error inside an iframe, instead of your website, i..e you'll lose iframed traffic altogether instead of jumping out of the iframe.
  • strix25
    strix25 over 2 years
    please fix typo in "document.referer" it should be "document.referrer" (double r). Other than that this seems to be a pretty good solution from my testing so far.