149

Some websites have code to "break out" of IFRAME enclosures, meaning that if a page A is loaded as an IFRAME inside an parent page P some Javascript in A redirects the outer window to A.

Typically this Javascript looks something like this:

<script type="text/javascript">
  if (top.location.href != self.location.href)
     top.location.href = self.location.href;
</script>

My question is: As the author of the parent page P and not being the author of the inner page A, how can I prevent A from doing this break-out?

P.S. It seems to me like it ought to be a cross-site security violation, but it isn't.

Jason Cohen
  • 81,399
  • 26
  • 107
  • 114

9 Answers9

138

With HTML5 the iframe sandbox attribute was added. At the time of writing this works on Chrome, Safari, Firefox and recent versions of IE and Opera but does pretty much what you want:

<iframe src="url" sandbox="allow-forms allow-scripts"></iframe>

If you want to allow top-level redirects specify sandbox="allow-top-navigation".

Pankrat
  • 5,206
  • 4
  • 31
  • 37
  • wait... what? They let you do this? I thought if a website wanted to break out, all browsers would let it. How are people supposed to keep their website out of iframes with this around? I'm not complaining though, awesome. – Farzher Dec 06 '12 at 22:45
  • 3
    Here's the antidote: http://blogs.msdn.com/b/ieinternals/archive/2010/03/30/combating-clickjacking-with-x-frame-options.aspx – Pankrat Dec 06 '12 at 23:21
  • Also, the browser might/will respect the header of the iframe src request: X-Frame-Options:SAMEORIGIN – Nasser Al-Wohaibi Feb 11 '13 at 13:10
  • 3
    @StephenSarcsamKamenar If you want to protect your site from being displayed in iframe there is **X-Frame-Options** header available with **SAMEORIGIN** value. Most modern browsers will not display site in iframe with this header. – Grzegorz Aug 06 '13 at 00:22
  • If some iframes are not working for you (such as embeded youtube), you can also add `allow-same-origin`. This helps: http://www.w3schools.com/tags/att_iframe_sandbox.asp – Christopher Bales Jun 25 '14 at 21:18
  • 4
    Unfortunately `sandbox` does not allow Flash or any other type of object in the sandboxed frame, making the `sandbox`feature useless in many cases. – oriadam May 21 '15 at 13:56
  • 1
    Websites should not "break out" to protest being included in an iframe. They can simply show a message or go blank. Unfortunately, allowing scripts to run in the iframe still opens you to a rogue iframe doing while(1) {} and other infinite loops. I wish each iframe could get its own thread. – Gregory Magarshak Mar 29 '17 at 15:53
  • This does prevent this by stopping the redirect entirely and providing an error. It would be nice to prevent the top level redirect, but still allow the redirect to happen in the iframe, but I guess that would make many things unsecure :( – ggedde Feb 22 '23 at 20:09
64

I use the sandbox attribute on the iframe element:

  • allow-forms allow form submission
  • allow-popups allows popups
  • allow-pointer-lock allows pointer lock
  • allow-same-origin allows the document to maintain its origin
  • allow-scripts allows JavaScript execution, and also allows features to trigger automatically
  • allow-top-navigation allows the document to break out of the frame by navigating the top-level window

Top navigation is what you want to prevent, so leave that out and it will not be allowed. Anything left out will be blocked

ex.

<iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="http://www.example.com"</iframe>
Flimm
  • 136,138
  • 45
  • 251
  • 267
adigioia
  • 1,188
  • 9
  • 10
  • 3
    Note that Flash (and any other objects) will also be blocked, with no option of allowing it. This "security feature" is preventing me from using sandbox all together – oriadam May 21 '15 at 13:39
44

Try using the onbeforeunload property, which will let the user choose whether he wants to navigate away from the page.

Example: https://developer.mozilla.org/en-US/docs/Web/API/Window.onbeforeunload

In HTML5 you can use sandbox property. Please see Pankrat's answer below. http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/

fasih.rana
  • 1,645
  • 1
  • 14
  • 27
  • 1
    iFrames *do* allow cross-domain communication, though, using `postMessage`. This isn't a security risk, but someone might care to know that this capability exists when they see your comment. :) – coreyward Feb 18 '12 at 15:19
  • It was not possible at the time of writing this answer. Thank you for pointing it out. – fasih.rana Feb 21 '12 at 16:30
  • @SirDarius could you please show an example, very highly appreciated. – user198989 Dec 03 '15 at 16:45
  • The user will not know why this confirmation appears, and will probably select a random response. I don't recommend using it. There are other solutions- the `sandbox`. – oriadam Dec 06 '15 at 23:10
  • You can actually include a message in the onbeforeunload popup. ;-) But let's not forget that displaying a page in an iframe, which doesn't want to be displayed in an frame, is content theft. There is a plethora of options for spoiling such an attempt, some of which involve Goatse. :-) – Mantriur Jan 18 '16 at 18:34
  • 1
    @fasih.rana The second article helped me a lot. Thank you ;) – MrD Oct 18 '17 at 10:39
  • 1
    Works for SCORM LMS integration (cloud.scorm.com). Three days of debug finally saved by your answer, thanks a lot to contribute to stackoverflow. – abenevaut Nov 26 '20 at 15:07
11

After reading the w3.org spec. I found the sandbox property.

You can set sandbox="", which prevents the iframe from redirecting. That being said it won't redirect the iframe either. You will lose the click essentially.

Example here: http://jsfiddle.net/ppkzS/1/
Example without sandbox: http://jsfiddle.net/ppkzS/

Parris
  • 17,833
  • 17
  • 90
  • 133
4

I know it has been a long time since question was done but here is my improved version it will wait 500ms for any subsequent call only when the iframe is loaded.

<script type="text/javasript">
var prevent_bust = false ;
    var from_loading_204 = false;
    var frame_loading = false;
    var prevent_bust_timer = 0;
    var  primer = true;
    window.onbeforeunload = function(event) {
        prevent_bust = !from_loading_204 && frame_loading;
        if(from_loading_204)from_loading_204 = false;
        if(prevent_bust){
            prevent_bust_timer=500;
        }
    }
    function frameLoad(){
        if(!primer){
            from_loading_204 = true;
            window.top.location = '/?204';
            prevent_bust = false;
            frame_loading = true;
            prevent_bust_timer=1000;
        }else{
            primer = false;
        }
    }
    setInterval(function() {  
        if (prevent_bust_timer>0) {  
            if(prevent_bust){
                from_loading_204 = true;
                window.top.location = '/?204';
                prevent_bust = false;
            }else if(prevent_bust_timer == 1){
                frame_loading = false;
                prevent_bust = false;
                from_loading_204 = false;
                prevent_bust_timer == 0;
            }



        }
        prevent_bust_timer--;
        if(prevent_bust_timer==-100) {
            prevent_bust_timer = 0;
        }
    }, 1);
</script>

and onload="frameLoad()" and onreadystatechange="frameLoad();" must be added to the frame or iframe.

Daniel
  • 23,129
  • 12
  • 109
  • 154
Luis Deleon
  • 49
  • 1
  • 1
2

In my case I want the user to visit the inner page so that server will see their ip as a visitor. If I use the php proxy technique I think that the inner page will see my server ip as a visitor so it is not good. The only solution I got so far is wilth onbeforeunload. Put this on your page:

<script type="text/javascript">
    window.onbeforeunload = function () {                       
         return "This will end your session";
    }
</script>

This works both in firefox and ie, thats what I tested for. you will find versions using something like evt.return(whatever) crap... that doesn't work in firefox.

radu
  • 21
  • 1
2

Since the page you load inside the iframe can execute the "break out" code with a setInterval, onbeforeunload might not be that practical, since it could flud the user with 'Are you sure you want to leave?' dialogs.

There is also the iframe security attribute which only works on IE & Opera

:(

user47087
  • 61
  • 3
1

try:

<iframe sandbox=" "></iframe>
Ashnet
  • 404
  • 5
  • 5
  • While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply – Matt Andruff May 06 '22 at 18:14
  • Stop any js script from runing iside iframe, // it works well for me – Ashnet May 08 '22 at 16:02
-1

By doing so you'd be able to control any action of the framed page, which you cannot. Same-domain origin policy applies.

Diodeus - James MacFarlane
  • 112,730
  • 33
  • 157
  • 176
  • 26
    I'm not asking to control what's inside the IFRAME. I'm asking to *prevent* what's inside the IFRAME from controlling me. – Jason Cohen Dec 15 '08 at 20:20