anti anti Frame Busting
In this post I presented a way to prevent a site you were (i)framing from frame busting out. Jeff Atwood recently contacted me to see if I knew a way to get around the prevention (to prevent sites from framing stackoverflow.com), which of course I didn’t, but I told him I’d think about it and see if I could come up with something. A week later I had come up with a few ideas but none actually worked.
See updates below for latest/best solution
But, due to some extra motivation from his post today (which links to my original post), I may have just come up with something.
It’s so stupid simple, but it seems to actually work. If you present an
I’ve just done a preliminary test of this in FF3 and IE7 and it worked in both. So I’m calling it, anti-anti-frame-busting is here!
Update: Jason brought up in a comment the issue of a user clicking OK before the page finished loading in which case the anti-frame-bust will still prevent you from busting. One thing you can do to make sure that the page loads extremely quickly so that no user will be able to click OK before that is to (pre-)cache it. Here’s an example:
You should have these headers on the page to bust out with.
First the framed page will do the initial load of the cached page in an iframe (which you can make hidden). Now that page will be cached and the next time you visit it the browser should make no network requests, loading the page completely from its local cache.
For this technique to work you’ll probly want to use it with a blank page which contains only a javascript/meta redirect to the actual page that was being framed. For example:
Update: On IE7 this caching technique alone is good enough to prevent anti-frame-busting. Meaning no
Update: The holy grail of anti-anti-frame-busting: This code, along with the caching technique described above, works in both FF3 and IE7 and has no negative user-experience (ie. alert boxes or frozen browsers):
See updates below for latest/best solution
But, due to some extra motivation from his post today (which links to my original post), I may have just come up with something.
1 | if (top != self) { |
2 | top.location.replace(document.location) |
3 | alert( 'busting you out, please wait...' ) |
4 | } | | |
It’s so stupid simple, but it seems to actually work. If you present an
alert()
box immediately after changing top.location
you prevent the browser from running any more JS, either from your framed site or from the framing site. But you don’t prevent the browser from loading the new page. So as long as the alert box stays up for a few seconds until the browser has loaded enough of the new page to stop running scripts on the old page, then the anti frame busting code never runs and you successfully are busted out once the user clicks OK on the alert.I’ve just done a preliminary test of this in FF3 and IE7 and it worked in both. So I’m calling it, anti-anti-frame-busting is here!
Update: Jason brought up in a comment the issue of a user clicking OK before the page finished loading in which case the anti-frame-bust will still prevent you from busting. One thing you can do to make sure that the page loads extremely quickly so that no user will be able to click OK before that is to (pre-)cache it. Here’s an example:
01 | <!-- this is the page being framed --> |
02 | < script > |
03 | function bust() { |
04 | if (top != self) { |
05 | // this page is now cached and will load immediately |
06 | top.location.replace("http://page-with-expires-headers.com/") |
07 | alert('busting you out, please wait...'); |
08 | } |
09 | } |
10 | </ script > |
11 | <!-- cache it! --> |
12 | |
You should have these headers on the page to bust out with.
1 | Expires: Sun, 19 Aug 2012 14:10:44 GMT <-- far enough in the future |
2 | Last-modified: Fri, 19 Jun 2009 04:24:20 GMT <-- now |
First the framed page will do the initial load of the cached page in an iframe (which you can make hidden). Now that page will be cached and the next time you visit it the browser should make no network requests, loading the page completely from its local cache.
For this technique to work you’ll probly want to use it with a blank page which contains only a javascript/meta redirect to the actual page that was being framed. For example:
1 | < html >< body > |
2 | redirecting... |
3 | < script > if (self == top) top.location='http://site-to-redirect-to.com/'; </ script > |
4 | </ body ></ html > |
Update: On IE7 this caching technique alone is good enough to prevent anti-frame-busting. Meaning no
alert()
is required after the top.location
change. At least this is true for a simple page which only consists of a javascript redirect:1 | < html > |
2 | < body > |
3 | we've busted out! redirecting... |
4 | < script > |
5 | // only redirect if we're busted out |
6 | if (top == self) top.location = "http://original-page.com"; |
7 | </ script > |
8 | </ body > |
9 | </ html > |
Update: The holy grail of anti-anti-frame-busting: This code, along with the caching technique described above, works in both FF3 and IE7 and has no negative user-experience (ie. alert boxes or frozen browsers):
1 | < script > |
2 | function bust() { |
3 | if (top != self) |
4 | setInterval("top.location.replace('http://cached-bust-out-page.com/with/redirect')",1); |
5 | } |
6 | </ script > |
7 | <!-- cache it! --> |
26 Comments »
RSS feed for comments on this post. TrackBack URI
But you are saying that the user has to wait a few moments before clicking “ok” for it to work? What about using a confirm() instead of an alert? That way we would have somewhat of a better mechanical turk, because perhaps users would be too quick to click “Ok.” Or maybe add a lot of text that they have to read first?
Hmmm, interesting stuff. Perhaps when I come off of the cold medications I am on I will play with this stuff…
Thanks for the info!
Comment by Jason Bunting — June 18, 2009 @ 11:03 pm
I think using the caching technique we may even be able to get away with no alert and possibly just a blocking while loop or something. I need to do some more testing.
Comment by coderrr — June 19, 2009 @ 4:28 am
Comment by Godfrey Chan — June 19, 2009 @ 10:09 am
Comment by coderrr — June 19, 2009 @ 10:25 am
what’s next?
Comment by coderrr — June 19, 2009 @ 10:47 am
Comment by coderrr — June 21, 2009 @ 11:08 am
Funny, I thought about a while loop too…
Hope this proves to be a solution, I look forward to the conclusion…
:)
Comment by Jason Bunting — June 19, 2009 @ 6:44 am
Pingback by Preventing Frame Busting and Click Jacking (UI Redressing) « coderrr — June 19, 2009 @ 7:46 am
Pingback by Firefox 3 internals, blocking alerts and XMLHttpRequests « coderrr — June 22, 2009 @ 7:25 pm
Anyhow, I have a couple of questions about the holy grail method. I tried implementing this technique in .NET 3.5 with C#. The log-in page for the app contains an iframe that points to the log-in page. The src tag for the iframe contains a query string param that lets the log-in page in the iframe know that it should set the headers as specified so the page will not cache. I also have the version of the log-in page in the iframe contain no frame busting code.
I would think that it this would allow me to not use a redirect page. The theory goes that the log-in page in the iframe is immediately cached by the browser. The parent log-in frame then contains the busting code as shown above.
Anyhow, my attempt does not work. In IE 7/8 you can hear the navigation sound as the page tries to break out but the frame maintains the upper hand.
My questions are this: What purpose does the redirect serve? It seems like the only reason you are using it is that it is cached and would load very, very quickly. Secondly, do you know of any server based attacks that would prevent the holy grail code? I can not find any script on the client’s frames. If there were script I could analyze what it’s doing and see if I could provide more info or perhaps a solution.
Thanks,
Mike
Comment by Mike — July 22, 2009 @ 11:37 am
You said “set the headers as specified so the page will not cache.”, did you mean to say so the page WILL cache?
Yes, the only reason for the redirect is so you can bust with a page which loads extremely fast so that the parent page doesn’t have time to stop the bust.
Even if you have the login page cached, if it has to load/render images, stylesheets, javascripts, etc. You would have to make sure all of those are cahced as well, and even then there will be time to render the page. It might be too slow.
I’d say try it with a very simple redirect page. Also I’d be interested to see the site which is framing you.
Comment by coderrr — July 23, 2009 @ 4:23 pm
Thanks for the reply. I kind of gave up on the whole thing for a bit because there was (and is) a bunch of stuff that we’re working on.
I was making some compliance updates and SEO enhancements to our main website (the one listed). After I relisted with all the major search engines I saw that we had a bunch of backlinks that were all framed. I decided to revisit the issue and saw that I created a flaw in my code.
I revisited my code and cleaned it up, saw the flaw and moved it our main site. It works like a charm. Thanks so much!
Mike G.
Comment by Mike — September 4, 2009 @ 4:31 pm
Comment by AC — March 24, 2010 @ 5:24 am
Pingback by Common Security Mistakes in Web Applications - Smashing Magazine — October 18, 2010 @ 12:46 pm
Pingback by Common Security Mistakes in Web Applications — October 18, 2010 @ 5:38 pm
Pingback by Design and Digital Media » Blog Archive » Common Security Mistakes in Web Applications — October 18, 2010 @ 8:22 pm
Pingback by Common Security Mistakes in Web Applications | LionWebMedia.com — October 19, 2010 @ 8:53 am
Pingback by Common Security Mistakes in Web Applications | Web Design Course Brisbane: Next Course Wed 20th Oct 2010 — October 20, 2010 @ 7:46 am
Pingback by Best and Cheap Solutions - Common Security Mistakes in Web Applications — October 27, 2010 @ 7:33 pm
Pingback by Common Security Mistakes in Web Applications « I.T News & Stuff — December 3, 2010 @ 4:47 am
how is the file structure and which code where. Do i need to triger bust function ?
Comment by Confuzed — May 6, 2011 @ 1:01 pm
Comment by Mezzeric — May 24, 2011 @ 1:49 pm
Comment by filipe — July 16, 2011 @ 5:20 pm
Comment by DemonTed1 — December 15, 2011 @ 6:03 am
Comment by Larry Holmes — January 5, 2012 @ 4:33 am
Comment by gerdnaschenweng — February 10, 2012 @ 2:07 pm