3

My content (including JS) is served in an iFrame that is then encapsulated in middleman's (distributor) iFrame that is then loaded by a publisher into his website. All 3 frames are served from different domains (cross-domain).

I need to identify the URL of the top frame (URL of the website) from within my iFrame. But I can only execute my JS in my iFrame, the middle man or the website publisher are unaffiliated, I can not ask them to put any script or in any way modify the source code of the middle iFrame or the website.

My question would be similar to this with the answer of:

var parentUrl = document.referrer;

except now there are 2 nested iFrames now so if I ask for document.referrer I will only get the URL of the middle man's iFrame, not the publisher's website.

So is it possible - for at least some modern browsers - to identify the top window's URL form inside of multiple nested cross-domain iFrames?

Community
  • 1
  • 1
daniel.sedlacek
  • 8,129
  • 9
  • 46
  • 77

1 Answers1

4

There is a stealthy way to get the domain in Chrome and Opera, (in multiple nested cross-domain iframes), though it is not possible in other browsers.

You need to use the 'window.location.ancestorOrigins' property, which seems to be a little trade secret within the advertising world. They may not like me posting it, though I think it's important for us to share information that may help others and ideally to share well documented and maintained examples of code.

Hence, I have created a snippet of code below to share and if you think you can improve the code or comments, please don't hesitate to edit the gist on Github so we can make it even better:

Gist: https://gist.github.com/ocundale/281f98a36a05c183ff3f.js

Code (ES2015):

// return topmost browser window of current window & boolean to say if cross-domain exception occurred
const getClosestTop = () => {
    let oFrame  = window,
        bException = false;

    try {
        while (oFrame.parent.document !== oFrame.document) {
            if (oFrame.parent.document) {
                oFrame = oFrame.parent;
            } else {
                //chrome/ff set exception here
                bException = true;
                break;
            }
        }
    } catch(e){
        // Safari needs try/catch so sets exception here
        bException = true;
    }

    return {
        'topFrame': oFrame,
        'err': bException
    };
};

// get best page URL using info from getClosestTop
const getBestPageUrl = ({err:crossDomainError, topFrame}) => {
    let sBestPageUrl = '';

    if (!crossDomainError) {
        // easy case- we can get top frame location
        sBestPageUrl = topFrame.location.href;
    } else {
        try {
            try {
                // If friendly iframe
                sBestPageUrl = window.top.location.href;
            } catch (e) {
                //If chrome use ancestor origin array
                let aOrigins = window.location.ancestorOrigins;
                //Get last origin which is top-domain (chrome only):
                sBestPageUrl = aOrigins[aOrigins.length - 1];
            }
        } catch (e) {
            sBestPageUrl = topFrame.document.referrer;
        }
    }

    return sBestPageUrl;
};

// To get page URL, simply run following within an iframe on the page:
const TOPFRAMEOBJ = getClosestTop();
const PAGE_URL = getBestPageUrl(TOPFRAMEOBJ);

If anybody would like the code in standard ES5, let me know, or simply run it through a converter online.

Oli C
  • 1,120
  • 13
  • 36