206

Okay, I have a page on and on this page I have an iframe. What I need to do is on the iframe page, find out what the URL of the main page is.

I have searched around and I know that this is not possible if my iframe page is on a different domain, as that is cross-site scripting. But everywhere I've read says that if the iframe page is on the same domain as the parent page, it should work if I do for instance:

parent.document.location
parent.window.document.location
parent.window.location
parent.document.location.href

... or other similar combos, as there seems to be multiple ways to get the same info.

Anyways, so here's the problem. My iframe is on the same domain as the main page, but it is not on the same SUB domain. So for instance I have

http:// www.mysite.com/pageA.html

and then my iframe URL is

http:// qa-www.mysite.com/pageB.html

When I try to grab the URL from pageB.html (the iframe page), I keep getting the same access denied error. So it appears that even sub-domains count as cross-site scripting, is that correct, or am I doing something wrong?

sideshowbarker
  • 62,215
  • 21
  • 143
  • 153
chronofwar
  • 2,063
  • 2
  • 13
  • 4

17 Answers17

402

Yes, accessing parent page's URL is not allowed if the iframe and the main page are not in the same (sub)domain. However, if you just need the URL of the main page (i.e. the browser URL), you can try this:

var url = (window.location != window.parent.location)
            ? document.referrer
            : document.location.href;

Note:

window.parent.location is allowed; it avoids the security error in the OP, which is caused by accessing the href property: window.parent.location.href causes "Blocked a frame with origin..."

document.referrer refers to "the URI of the page that linked to this page." This may not return the containing document if some other source is what determined the iframe location, for example:

  • Container iframe @ Domain 1
  • Sends child iframe to Domain 2
  • But in the child iframe... Domain 2 redirects to Domain 3 (i.e. for authentication, maybe SAML), and then Domain 3 directs back to Domain 2 (i.e. via form submission(), a standard SAML technique)
  • For the child iframe the document.referrer will be Domain 3, not the containing Domain 1

document.location refers to "a Location object, which contains information about the URL of the document"; presumably the current document, that is, the iframe currently open. When window.location === window.parent.location, then the iframe's href is the same as the containing parent's href.

The Red Pea
  • 12,346
  • 12
  • 77
  • 112
Vaibhav
  • 4,037
  • 2
  • 11
  • 3
  • @Ash it'll if the window and the parent window location's are different, you're inside of an iframe. In that case, it takes the referrer of the iframe. Otherwise, it's the main window, thus takes document.location (referrer is invalid here, since it'd be the previous page and not the parent). – Lumbendil Oct 18 '13 at 18:17
  • 1
    @jepser that is because your iframe is inside that iframe. you will never have access to the top frame with that one in the middle. nested cross domain iframes is wrong on so many levels. but you may be able to get around that if you set `document.domain` on the top frame and the inner-most one. maybe. – gcb Oct 26 '13 at 01:46
  • This answer combined with http://stackoverflow.com/a/5697801/216084 gets the job done. –  Dec 09 '13 at 10:15
  • 2
    Or, slightly more compactly: `var url = (parent !== window) ? document.referrer : document.location;` – thekingoftruth Dec 18 '14 at 11:17
  • 2
    Please note that it doesn't work if the container is located on your localhost (or more generally, if this page is not open by a web server) or called by file://. – Guillaume Renoult Feb 05 '15 at 06:04
  • 6
    It should be noted that this can be defeated with the [`Referer-Policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) header. – Dan Atkinson Mar 15 '17 at 16:55
  • 2
    This doesn't seem to work with Edge browser - the referrer will be an empty string.. https://stackoverflow.com/questions/24169219/on-ie-10-will-document-referrer-be-blank-when-read-inside-an-iframe – Davide Orazio Montersino May 23 '17 at 09:59
  • 2
    @thekingoftruth even more concise: `var url = (self===top) ? document.URL : document.referrer;` (two changes: (1) using positive instead of negative check; (2) `document.location` is an object, so you need to use `document.location.href` or `document.URL`). – thdoan Oct 19 '18 at 04:28
  • Will this work if the container is running on ngrok? – Sparlarva Dec 28 '18 at 21:45
  • Tried this after several other solutions and it worked! In my case, the script was executed inside a frame located at the main page, with different urls but same host. – jcf Jul 04 '19 at 09:28
  • This solution won't work if the parent page has ` ` – Miguel Mota May 07 '20 at 22:34
  • This solution does not wok. Chrome is blocking redirect. – Kamlesh Jan 02 '21 at 07:38
55

I just discovered a workaround for this problem that is so simple, and yet I haven't found any discussions anywhere that mention it. It does require control of the parent frame.

In your iFrame, say you want this iframe: src="http://www.example.com/mypage.php"

Well, instead of HTML to specify the iframe, use a javascript to build the HTML for your iframe, get the parent url through javascript "at build time", and send it as a url GET parameter in the querystring of your src target, like so:

<script type="text/javascript">
  url = parent.document.URL;
  document.write('<iframe src="http://example.com/mydata/page.php?url=' + url + '"></iframe>');
</script>

Then, find yourself a javascript url parsing function that parses the url string to get the url variable you are after, in this case it's "url".

I found a great url string parser here: http://www.netlobo.com/url_query_string_javascript.html

rogerdpack
  • 50,731
  • 31
  • 212
  • 332
Gregory Lewis
  • 551
  • 4
  • 2
  • This answer combined with http://stackoverflow.com/a/7739035/216084 gets the job done. –  Dec 09 '13 at 10:15
  • 2
    This was a wonderful suggestion. For those who are writing the parent html iframe code this would foot the bill. We used something very similar in our pixel software. – Ligemer Nov 25 '14 at 00:30
  • Thank you!! This is an effective work-around that still respects cross-site rules. – theUtherSide Sep 11 '15 at 22:07
  • But do you rewrite all the urls in the html at the server? Because otherwise when an user clicks a link in the iFrame it will still not be accessable. – Roel Apr 11 '16 at 09:41
  • @Roel you could write them all at server time (in essence, "hard code" this answer), or this answer you could do in javascript, for instance after the page loads it injects the desired iframes. – rogerdpack Oct 28 '16 at 18:39
  • document.write is considered sort of bad practice for a variety of reasons. It might work, but you should use it with caution. Here's an interesting blog about it: https://blog.dareboost.com/en/2016/09/avoid-using-document-write-scripts-injection/. Along with: https://stackoverflow.com/questions/802854/why-is-document-write-considered-a-bad-practice and https://stackoverflow.com/questions/18789190/why-not-document-write – Carnix Apr 11 '18 at 16:27
  • `Uncaught DOMException: Blocked a frame with origin "https://blah.net" from accessing a cross-origin frame.` – Ken Sharp Jul 30 '20 at 19:06
37

If your iframe is from another domain, (cross domain), you will simply need to use this:

var currentUrl = document.referrer;

and - here you've got the main url!

ParPar
  • 6,660
  • 7
  • 40
  • 52
  • That didn't work in my case as I think the iFrame itself has been dynamically generated or did some other trickery. I did not get the answer I expected at any rate. – Muskie Jun 17 '13 at 23:30
  • this should work in all browsers. Unless in newer browsers if you send Sandboxing parameters, but i doubt this is the case. This works regardless of cross domain. – gcb Oct 26 '13 at 01:41
  • If the page inside the iframe reloaded itself via javascript (e.g. `window.location.reload(true)`) this doesn't work anymore. Then referrer is the URL of the iframe itself. – mori Mar 26 '19 at 07:57
27

The following line will work: document.location.ancestorOrigins[0] this one returns the ancestor domain name.

Vineeth Sai
  • 3,113
  • 7
  • 19
  • 28
  • Following changes made to Chrome, this is now the correct answer for a lot of browsers. – Dan Atkinson Apr 23 '19 at 16:41
  • 1
    Not the full url though. Only the domain – TheMaster Jul 22 '19 at 16:00
  • 2
    `document.location.ancestorOrigins` returns `undefined` for me – Miguel Mota May 07 '20 at 22:32
  • 4
    Regarding browser support, specifically, as of July 2020, ancestorOrigins is not yet supported in Firefox due to privacy concerns. Bugzilla feature request and discussion: https://bugzilla.mozilla.org/show_bug.cgi?id=1085214. Browser support: https://caniuse.com/#search=ancestorOrigins – colin moock Jul 04 '20 at 18:24
26

You're correct. Subdomains are still considered separate domains when using iframes. It's possible to pass messages using postMessage(...), but other JS APIs are intentionally made inaccessible.

It's also still possible to get the URL depending on the context. See other answers for more details.

Dan Herbert
  • 90,244
  • 46
  • 174
  • 217
  • 4
    you CAN interact between the 2. But you must add the following script on both parent and iframe: – George Apr 03 '15 at 16:01
20

For pages on the same domain and different subdomain, you can set the document.domain property via javascript.

Both the parent frame and the iframe need to set their document.domain to something that is common betweeen them.

i.e. www.foo.mydomain.com and api.foo.mydomain.com could each use either foo.mydomain.com or just mydomain.com and be compatible (no, you can't set them both to com, for security reasons...)

also, note that document.domain is a one way street. Consider running the following three statements in order:

// assume we're starting at www.foo.mydomain.com
document.domain = "foo.mydomain.com" // works
document.domain = "mydomain.com" // works
document.domain = "foo.mydomain.com" // throws a security exception

Modern browsers can also use window.postMessage to talk across origins, but it won't work in IE6. https://developer.mozilla.org/en/DOM/window.postMessage

Richard Neil Ilagan
  • 14,133
  • 5
  • 44
  • 64
user409021
  • 236
  • 1
  • 2
  • 3
    Please accept this as the answer, now that this is both possible and that this answer is coming up in Google searches. – Metagrapher Dec 08 '13 at 23:21
13

Try it:

document.referrer

When you change you are in a iframe your host is "referrer".

  • Today, in Chrome, this is not returning the full URL. When `example.com?abc=123` loads an iframe, and you run `document.referrer` on the iframe, it only gives `example.com` and strips the `?abc=123` part. – KingJulian Dec 21 '20 at 20:12
2

I've found in the cases where $_SERVER['HTTP_REFERER'] doesn't work (I'm looking at you, Safari), $_SERVER['REDIRECT_SCRIPT_URI'] has been a useful backup.

Dan
  • 43
  • 5
2
var url = (window.location != window.parent.location) ? document.referrer: document.location;

I found that the above example suggested previously worked when the script was being executed in an iframe however it did not retrieve the url when the script was executed outside of an iframe, a slight adjustment was required:

var url = (window.location != window.parent.location) ? document.referrer: document.location.href;
  • 2
    If you outside the iframe then you are running the script ON the parent frame, you don't need to check anything. – Art3mix Dec 08 '18 at 15:11
2

I've had issues with this. If using a language like php when your page first loads in the iframe grab $_SERVER['HTTP_REFFERER'] and set it to a session variable.

This way when the page loads in the iframe you know the full parent url and query string of the page that loaded it. With cross browser security it's a bit of a headache counting on window.parent anything if you you different domains.

Didier Ghys
  • 29,364
  • 9
  • 67
  • 76
1

The problem with the PHP $_SERVER['HTTP_REFFERER'] is that it gives the fully qualified page url of the page that brought you to the parent page. That's not the same as the parent page, itself. Worse, sometimes there is no http_referer, because the person typed in the url of the parent page. So, if I get to your parent page from yahoo.com, then yahoo.com becomes the http_referer, not your page.

TARKUS
  • 1,896
  • 5
  • 30
  • 49
1

In chrome it is possible to use location.ancestorOrigins It will return all parent urls

Gena Moroz
  • 910
  • 5
  • 7
1

I couldnt get previous solution to work but I found out that if I set the iframe scr with for example http:otherdomain.com/page.htm?from=thisdomain.com/thisfolder then I could, in the iframe extract thisdomain.com/thisfolder by using following javascript:

var myString = document.location.toString();
var mySplitResult = myString.split("=");
fromString = mySplitResult[1];
Paul
  • 1,554
  • 5
  • 17
  • 24
0

there is a cross browser script for get parent origin:

private getParentOrigin() {
  const locationAreDisctint = (window.location !== window.parent.location);
  const parentOrigin = ((locationAreDisctint ? document.referrer : document.location) || "").toString();

  if (parentOrigin) {
    return new URL(parentOrigin).origin;
  }

  const currentLocation = document.location;

  if (currentLocation.ancestorOrigins && currentLocation.ancestorOrigins.length) {
    return currentLocation.ancestorOrigins[0];
  }

  return "";
}

This code, should work on Chrome and Firefox.

-2

I know his is super old but it blows my mind no one recommended just passing cookies from one domain to the other. As you are using subdomains you can share cookies from a base domain to all subdomains just by setting cookies to the url .basedomain.com

Then you can share whatever data you need through the cookies.

Bruce
  • 910
  • 1
  • 6
  • 24
-3

This worked for me to access the iframe src url.

window.document.URL
user1503606
  • 2,818
  • 10
  • 36
  • 69
-4

Get All Parent Iframe functions and HTML

var parent = $(window.frameElement).parent();
        //alert(parent+"TESTING");
        var parentElement=window.frameElement.parentElement.parentElement.parentElement.parentElement;
        var Ifram=parentElement.children;      
        var GetUframClass=Ifram[9].ownerDocument.activeElement.className;
        var Decision_URLLl=parentElement.ownerDocument.activeElement.contentDocument.URL;
K.Dᴀᴠɪs
  • 9,384
  • 11
  • 31
  • 39
  • I don't suppose you can expand this answer for those of us who don't use jQuery (a growing number, I should point out, since jQuery has become increasing unnecessary over the last few years). At the very least, I suggest making it clear this answer is dependent on jQuery and the OP didn't mention jQuery at all. – Carnix Apr 11 '18 at 16:29