I've been investigating frame breaking code recently and have come across some really bizarre behavior related to the same origins policy that I am having trouble understanding.
Suppose I've got a page Breaker.html on domain A, and a page Container.html on domain B. The example frame breaker code would go into Breaker.html, like below:
if (top !== self) top.location.href = self.location.href;
This will successfully break Breaker.html out of Container.html, but I don't understand why it should. From my reading of the same origins policy, top.location
shouldn't be accessible at all, since Container.html is on a different domain than Breaker.html. Even weirder, it appears that top.location write-only:
// Fails if Container.html is on a different domain than Breaker.html
alert(top.location);
This is problematic to me because I'm trying to write code that allows my page to be in an iframe, but only if it's on the same domain as its parent (or is on a configured allowable domain) . However, it seems to be impossible to determine this, since the same origins policy denies me access to the parent's location.
So I've got two questions, basically:
Why does the above frame breaker code work at all?
Is there any way to break frames conditionally, or is the only check one can do is whether
top !== self
? (In particular, I want to be able to read the domain, so that I can provide a list of allowable domains; simply checking whether I'm in the same domain or not would not be ideal.)
This is for question number 2: If you want to take HREF of parent.location (not top.location), you can do this:
Basically what this code does is:
[1] Checking if parent frame is the top one because you can take only parent's HREF even if it is not the top frame.
[2] Checking if iframe's history was blank before loading its source, because if not... document.referrer will return the last HREF in this frame history.
After that, you have a new problem: in case history.length's value is more than one, you can use a whitelist of hostnames to check if it has to be opened or not:
Note that you another option: can use a landing page to check if the "first" page has to open or not, use this code:
Doing it this way, the "first" page will replace history's first (in this case it is first) value. That code is asuming "example.com" is your domain.
FOr your answer to number 1: In terms of security, there is a big difference between read access and write access. Being able to read top.location.href is a security problem. Being able to write to top.location.href is not.
As for the answer to your question, I don't know javascript well enough to be sure, but one idea would be to assumine that if reading top.location fails (check for exceptions), it is on a different domain.
The answer to question 1 is that the equality operator can be used against top.location.href for legacy reasons. Breaker.html cannot read top.location.href but it can compare it with another value.
The answer to question 2 then becomes no, you must use the !== to part because you won't be able to do a substring on top.location.href from a cross domain breaker.html.
I could be wrong but that's my understand of the current iframe world.