Iframes are known for sandboxing the JavaScript inside the iframe. But, is the converse true? Do iframes protect their contents from JavaScript outside (on the hosting webpage)? My basic tests suggest that they do, but I can't find explicit documentation on this.
If you're curious, here's my use case:
A browser extension must display sensitive text on a third-party, untrusted webpage. Ideally, it will inject the text such that it cannot be accessed by JavaScript running on the untrusted webpage. The user may see it; the JavaScript may not.
The mechanisms for separating the JavaScript environments of the parent document and the iframed document work the same way in both directions.
They have their own environments
Access to the other environment is possible via parent and frameNode if they contain documents that are on the same origin
postMessage can be used to pass strings between them even if they are not on the same origin (but must be listened for by the document receiving the message).
A browser extension must display sensitive text on a third-party, untrusted webpage. Ideally, it will inject the text such that it cannot be accessed by JavaScript running on the untrusted webpage. The user may see it; the JavaScript may not.
This sounds like something better addressed using a mechanism that displays the text in the browser chrome rather than embedded in the page itself, e.g. with the Chrome popup api.
As best I can tell, the content is protected.
Iframes' contents are (by default) treated as if from a different origin. This brings the same-origin policy into play, preventing each page from accessing the others' DOM.
However, if you do <iframe sandbox="allow-same-origin">...</iframe>), then the iframe's contents can be accessed. Here's an important question:
Can malicious JavaScript programmatically set allow-same-origin to get into an iframe?
I don't know of explicit documentation on this, but my tests in Google Chrome say that programmatically changing the sandbox attribute has no effect on the iframe. Yes, you can dynamically change the sandbox attribute, but it has no effect.
Related
Why are iframes considered dangerous and a security risk? Can someone describe an example of a case where it can be used maliciously?
The IFRAME element may be a security risk if your site is embedded inside an IFRAME on hostile site. Google "clickjacking" for more details. Note that it does not matter if you use <iframe> or not. The only real protection from this attack is to add HTTP header X-Frame-Options: DENY and hope that the browser knows its job.
If anybody claims that using an <iframe> element on your site is dangerous and causes a security risk, they do not understand what <iframe> element does, or they are speaking about possibility of <iframe> related vulnerabilities in browsers. Security of <iframe src="..."> tag is equal to <img src="..." or <a href="..."> as long there are no vulnerabilities in the browser. And if there's a suitable vulnerability, it might be possible to trigger it even without using <iframe>, <img> or <a> element, so it's not worth considering for this issue.
In addition, IFRAME element may be a security risk if any page on your site contains an XSS vulnerability which can be exploited. In that case the attacker can expand the XSS attack to any page within the same domain that can be persuaded to load within an <iframe> on the page with XSS vulnerability. This is because vulnerable content from the same origin (same domain) inside <iframe> is allowed to access the parent content DOM (practically execute JavaScript in the "host" document). The only real protection methods from this attack is to add HTTP header X-Frame-Options: DENY and/or always correctly encode all user submitted data (that is, never have an XSS vulnerability on your site - easier said than done).
However, be warned that content from <iframe> can initiate top level navigation by default. That is, content within the <iframe> is allowed to automatically open a link over current page location (the new location will be visible in the address bar). The only way to avoid that is to add sandbox attribute without value allow-top-navigation. For example, <iframe sandbox="allow-forms allow-scripts" ...>. Unfortunately, sandbox also disables all plugins, always. For example, historically Youtube couldn't be sandboxed because Flash player was still required to view all Youtube content. No browser supports using plugins and disallowing top level navigation at the same time. However, unless you have some very special reasons, you cannot trust any plugins to work at all for majority of your users in 2021, so you can just use sandbox always and guard your site against forced redirects from user generated content, too. Note that this will break poorly implemented content that tries to modify document.top.location. The content in sandboxed <iframe> can still open links in new tabs so well implemented content will work just fine. Also notice that if you use <iframe sandbox="... allow-scripts allow-same-origin ..." src="blog:..."> any XSS attack within the blob: content can be extended to host document because blob: URLs always inherit the origin of their parent document. You cannot wrap unfiltered user content in blob: and render it as an <iframe> any more than you can put that content directly on your own page.
Example attack goes like this: assume that users can insert user generated content with an iframe; an <iframe> without an attribute sandbox can be used to run JS code saying document.top.location.href = ... and force a redirect to another page. If that redirect goes to a well executed phishing site and your users do not pay attention to address bar, the attacker has a good change to get your users to leak their credentials. They cannot fake the address bar but they can force the redirect and control all content that users can see after that. Leaving allow-top-navigation out of sandbox attribute value avoids this problem. However, due historical reasons, <iframe> elements do not have this limitation by default, so you'll be more vulnerable to phishing if your users can add <iframe> element without attribute sandbox.
Note that X-Frame-Options: DENY also protects from rendering performance side-channel attack that can read content cross-origin (also known as "Pixel perfect Timing Attacks").
That's the technical side of the issue. In addition, there's the issue of user interface. If you teach your users to trust that URL bar is supposed to not change when they click links (e.g. your site uses a big iframe with all the actual content), then the users will not notice anything in the future either in case of actual security vulnerability. For example, you could have an XSS vulnerability within your site that allows the attacker to load content from hostile source within your iframe. Nobody could tell the difference because the URL bar still looks identical to previous behavior (never changes) and the content "looks" valid even though it's from hostile domain requesting user credentials.
As soon as you're displaying content from another domain, you're basically trusting that domain not to serve-up malware.
There's nothing wrong with iframes per se. If you control the content of the iframe, they're perfectly safe.
I'm assuming cross-domain iFrame since presumably the risk would be lower if you controlled it yourself.
Clickjacking is a problem if your site is included as an iframe
A compromised iFrame could display malicious content (imagine the iFrame displaying a login box instead of an ad)
An included iframe can make certain JS calls like alert and prompt which could annoy your user
An included iframe can redirect via location.href (yikes, imagine a 3p frame redirecting the customer from bankofamerica.com to bankofamerica.fake.com)
Malware inside the 3p frame (java/flash/activeX) could infect your user
IFRAMEs are okay; urban legends are not.
When you "use iframes", it doesn't just mean one thing. It's a lexical ambiguity. Depending on the use case, "using iframes" may mean one of the following situations:
Someone else displays your content in an iframe
You display domeone else's content in an iframe
You display your own content in an iframe
So which of these cases can put you in risk?
1. Someone else displays your content
This case is almost always referred to as clickjacking - mimicking your site's behaviour, trying to lure your users into using a fake UI instead of the real site. The misunderstanding here is that you using or not using iframes is irrelevant, it's simply not your call - it's someone else using iframes, which you can do nothing about. Btw, even they don't need them specifically: they can copy your site any other way, stealing your html, implementing a fake site from scratch, etc.
So, ditching iframes in attempt to prevent clickjacking - it makes exactly zero sense.
2. You display someone else's content
Of the three above, this is the only one that's somewhat risky, but most of the scary articles you read all the time come from a world before same-origin policy was introduced. Right now, it's still not recommended to include just any site into your own (who knows what it will contain tomorrow?), but if it's a trusted source (accuweather, yahoo stock info etc), you can safely do it. The big no-no here is letting users (therefore, malicious users) control the src of the iframe, telling it what to display. Don't let users load arbitrary content into your page, that's the root of all evil. But it's true with or without iframes. It has nothing to do with them; it could happen using a script or a style tag (good luck living without them) - the problem is you let them out. Any output on your site containing any user-given content is RISKY. Without sanitizing (de-HTMLifying) it, you're basically opening your site up for XSS attacks, anyone can insert a <script> tag into your content, and that is bad news. Like, baaaad news.
Never output any user input without making dead sure it's harmless.
So, while iframes are innocent again, the takeaway is: don't make them display 3rd-party content unless you trust the source. In other words, don't include untrusted content in your site. (Also, don't jump in front of fast-approaching freight trains. Duuh.)
3. You display your own content in an iframe
This one is obviously harmless. Your page is trusted, the inner content of the iframe is trusted, nothing can go wrong. Iframe is no magic trick; it's just an encapsulation technique, you absolutely have the right to show a piece of your content in a sandbox. It's much like putting it inside a div or anything else, only it will have its own document environment.
TL;DR
Case 1: doesn't matter if you use iframes or not,
Case 2: not an iframe problem,
Case 3: absolutely harmless case.
Please stop believing urban legends. The truth is, iframe-s are totally safe. You could as well blame script tags for being dangerous; anything can cause trouble when maliciously inserted in a site. But how did they insert it in the first place? There must be an existing backend vulnerability if someone was able to inject html content into a site. Blaming one piece of technology for a common attack (instead of finding the real cause) is just a synonym for keeping security holes open. Find the dragon behind the fire.
Unsanitized output is bad; iframes are not.
Stop the witch-hunt.
UPDATE:
There is an attribute called sandbox, worth checking out: https://www.w3schools.com/tags/att_sandbox.asp
UPDATE 2:
Before you comment against iframes - please think about hammers. Hammers are dangerous. They also don't look very nice, they're difficult to swim with, bad for teeth, and some guy in a movie once misused a hammer causing serious injuries. Also, just googled it and tons of literature says mortals can't even move them. If this looks like a good reason to never ever use a hammer again, iframes may not be your real enemy. Sorry for going offroad.
"Dangerous" and "Security risk" are not the first things that spring to mind when people mention iframes … but they can be used in clickjacking attacks.
iframe is also vulnerable to Cross Frame Scripting:
https://www.owasp.org/index.php/Cross_Frame_Scripting
I've got a page with an iframe. The page and the source of the iframe are in different domains. Inside the iframe I'm using a rich text editor called CuteEditor (which has turned out to be not so cute). There are certain javascript functions in CuteEditor which try to access 'document' but the browser denies access since they're not in the same domain.
Here's the exact error:
Permission denied to access property 'document'
http://dd.byu.edu/plugins/cuteeditor_files/Scripts/Dialog/DialogHead.js
Line 1
Editing the javascript is out of the question because it's been minfied and obfuscated so all the variable names are cryptic.
Using a different editor is currently out of the question because this is a work project and this is the editor I've been told to use.
Is there a way to keep the iframe self-contained? So it does everything inside the iframe and doesn't try to break out to the parent frame?
If the child iframe is loaded from a different domain, then it will not be able to access the parent page or DOM.
However, there is a still a possible vulnerability to man-in-the-middle attack as follows. Suppose your page loads off http://yoursite.com and the iframe goes to http://badsite.org
first http://badsite.org redirects to http://yoursite.com/badpage
This is the step that requires a man-in-the-middle attack. The attacker must either be able to get between the user and yoursite.com, or control the answers to your DNS lookup. This is easier than it sounds -- anyone who has administrative control over a public WiFi access point could do it (think Starbucks, hotels, airports.) The goal is to serve the content of http://yoursite.com/badpage from the attacker's site, not your actual site.
The attacker can then serve whatever malicious code they like from the (fake) http://yoursite.org/badpage. Because this is in the same domain as the main page, it will have access to the parent DOM.
The HTML5 iframe sandbox attribute seems to be the way to avoid this. You can read the spec, but the best description might be here.
This seems to be supported on Chrome, IE10, FireFox, Safari.
The spec says that if the "allow-same-origin" attribute is not set, "the content is treated as being from a unique origin." This should prevent your child iframe from accessing any part of the parent's DOM, no matter what the browser thinks the URL is.
You shouldn't need to worry about that happening.
The only way iframes can talk cross-origin is with postMessage, and that's only possible if you're listening to that domain directly.
https://developer.mozilla.org/en/DOM/window.postMessage
I understand the reason for forbidding iframes from accessing the top window, but the other way around it seems a bit unnecessary and restricting of innovative applications.
It's actually more dangerous to be able to access content in a child window, because the top window is "in control" (i.e., the top window chooses which page to display in the iframe). Technically the threat is the same either way, but it makes it a lot easier for a malicious web site if it can host it's own iframes, rather than hope it gets embedded in a target site.
By preventing access to the contents when they're cross-domain, it prevents a whole host of XSRF and XSS attacks. For example, if I was running a malicious web site, I could simply place hidden iframes on my page to dozens of popular sites, whether they be social networking, e-mail, financial, etc. If you were already authenticated against any of them, your browser would send your session cookies along, even within the iframe, and the iframe would serve an authenticated page with secure content.
This is obviously really bad if the parent window can scrape the child window or inject new JavaScript into the child window to be executed.
Because this would allow you to relatively invisibly put a site like paypal.com in an iframe and then change that site, thus deceiving the user (and perhaps capturing the credentials or bank account information entered).
One web site is not allowed to modify the behavior of another site, purely from the web. Modifying the behavior of a site can be done with browser plug-ins or with add-on frameworks like greasemonkey, but the user has to choose to install those capabilities and there's an assumption that they only install capabilities they trust (not always true, but that's what it relies on).
It's potentially even more dangerous for the top level frame to be able to access the embedded frames because the top level frame gets to decide which sites to put in the embedded frames and thus attack/mess with.
It's the same issue as child to parent. You don't want the chance of malicious sites messing with the content of valid sites they just happen to be in the same browser window with.
Getting directly the current iframe's URL, in javascript, is not possible due to security restriction.
Is there a way to override this restriction?
Using ActiveX control?
Changing the browser's security options?
Using HTML5?
Using flash?
Using server side scripting?
Getting directly the current iframe's URL, in javascript, is not possible due to security restriction
If you mean cross-domain IFrames, and you have no way of controlling the inlying page, then this is correct.
As far as I know, no, there is no way to get around this.
The only way I can think of - and you don't want to go down that road - is proxying every page inside the iframe through a local server script, rewriting every link and action within each page to go through the proxy, too. But that is hugely difficult, comes with a shitload of things to be aware of, and is not a real option - many modern sites will simply break if proxied that way.
As I understand it if you have no control of the frame you are not supposed to know what is going on in this frame. So, knowing it would be a security bug and should be fixed. Browsers are designed to not allow the page spy on what you are doing in another page.
If you have control over iFrame there are some options for you
There is a discussion here:
How do I get the current location of an iframe?
basically
var iframe = document.getElementById('loader').src
You can actually get the location if iframe is located at the same server. If it is located at a different server the only way to go is to rewrite URLs like some sites do. It is not easy to do though
You can also do HTML5 cross-window communication:
http://ajaxian.com/archives/cross-window-messaging-with-html-5-postmessage
I know that, for security reasons, javascript can't read the contents of an iframe if it belongs to a different domain. This makes sense, given that the entire page could be an iframe with snooping scripts outside of the frame.
The question is - are there equal limitations in the other direction? Can javascript within an iframe (from a different domain) read and manipulate the dom in its parent window?
Thanks!
You can't.
This would be a security hole. Now that everyone is crazy adding facebook iframes to their sites, imagine if javascript from FB could interact with your page ;)
Anyway, i set up a small example, and got the same origin warning when i tried to get a parent's div from inside the iframe (which was in another domain)
If you want to use this in a two domains that you own (not trying to attack anyone) you can do that using ajax as described Here.