Why does the `onload` event not fire on nested iframes with framebusting?

842 views Asked by At

Consider the following three pages.

  1. Foo.html is opened locally in the browser, and so has a URL with prefix file:///.
  2. Bar.html is in the same directory has Foo.html.
  3. Bar2.html lives in /var/www and I am running Apache on localhost.

Foo.html

<html>
  <head>
  <script>
  foo = function() {
    alert("frame changed");
  };
  </script>
  </head>

  <body>
  <iframe width="200" height="300" src="Bar.html" id="my-iframe" onLoad="foo" /> 
  </body>
</html>

Bar.html

<html>
  <body>
  <iframe width="200" height="300" src="http://localhost/Bar2.html" id="my-iframe" /> 
  </body>
</html>

Bar2.html

<html>
  <head>
  <script>
  if (top.location != self.location){
      parent.location = self.location;
  }
  </script>
  </head>
  <body>
  <button type="button" onclick="document.location.href='http://bing.com'">Hello World</button>
  </body>
</html>

When Foo.html is loaded in Firefox, by running firefox /path/to/Foo.html on the command line, the frame busting code in Bar2.html breaks out of Bar.html. At this point, the user gets an alert frame changed.

When I click the button, the iframe changes (the button vanishes), but I do not get an alert.

Why is the onLoad not firing the second time when the page changes?

2

There are 2 answers

2
tomysshadow On

Your script

  if (top.location != self.location){
      parent.location = self.location;
  }

will run on Bar2.htm and change the location of its parent (previously Bar.htm). Then the alert comes. Then, the script will run in the parent (previously Bar.htm) but top.location is still not equal to self.location . (top.location is now equal to Foo.htm and self.location is equal to Bar.htm ) so when you click the button, the parent page has been redirected to Bar2.htm . Meaning the alert code and the iframe is gone.

4
Travis J On

The issue lays in the fact that when Bar2.html is being loaded by the iframe in Bar.html this condition is false

if (top.location != self.location)

As a result, when Bar.html is loading Bar2.html this is called

parent.location = self.location;

Which issues a redirect in the page and cancels the affect of the onload event since the page technically never finished loading.