iFrames - The good, the bad and the ugly
Frequently I got asked about the security considerations regarding iframes - so I decided to write up my opinion on them. When you search for “iframe” and “security” you’ll find quite a lot of links dealing with possible usage of iframes in attack vectors. Many interesting things are possible this way. Starting from injection content, sending requests across domain boundaries or even port scanning the adjacent lan via CSS or JAVASCRIPT. You may find more information on this here.
In the following sections I will use the following terms repeatedly. Therefore it’s time to define them now: Parent: It describes the main site that includes one or more iframes. It is assumed that you control this site
Guest:
It describes the include site which is rendered inside an iframe within the parent. There may be on or more guests to one parent.
Cross Domain:
Such an scenario is always valid when the source (“src”) argument of the iframe points to an other domain than the parent. This is for example the case when you include 3rd-Party-Adds in your Parent.
LAN:
Here I am talking about your internal network access through the web-server hosting your parent-site.
Cross Domain Attacks (GUEST -> PARENT):
This leaves us with the impression that “iframes” are evil and dangerous things. However, this does not need to be the case. Depending to what extend you’re able control the content of an iframe it may be considered as “harmless” - and I am well aware that there is no such thing as “harmless” :)
Mozilla published a well written summary on “how to use iframes securely”. Especially as long as you stick to enforcing the same origin policy (X-Frame Headers) and ensure that no iframe is included in the “guest”-iframe the sources the parent-domain you will minimize cross domain attacks.
Cross Domain Attacks (PARENT -> GUEST):
So far we considered the situation when the included iframe was evil. However, assuming that an attacker is able to inject javascript, css or html (XSS / CSRF) into the parent site, she will be able to access the guest. The access may be granted either through direct DOM access or via an guest-iframe within the guest pointing to the parent’s domain. Especially the later is commonly used in modern AJAX Web Applications to avoid the “Same Origin Policy” and therefore to establish cross domain communication. Just think about portals and mash-ups. Besides you do not actually need to access the guest directly - have you considered registering a key-stroke-logger with the main browser window?
SSL vs. NON-SSL:
And this brings us to the good old question about SSL. Regardless of the flaws included in SSL/TLS it is not a wise idea to include http-guests in an https-parent or the other way round. By combining a non-ssl and an ssl-protected element you reduce the overall security to “http” - which is NONE! So? Stay away from it and use either http- or https-only combinations.
HTML5 - Sandbox:
A modern browser includes what’s called the HTML5-Sandbox. This feature allows you to restrict what an iframe can do, or better what can be done within an iframe by simply adding an additional attribute to the iframe-tag. This attribute is called “sandbox” and can have one or more of the following values:
- allow-forms: Do you want to allow form-posts from the guest?
- allow-scripts: Do you want the guest to execute scripts?
- allow-same-origin: When using the sandbox guest have no access to the parent-dom, unless you activate allow-same-origin. Then guest coming from the same-domain as the parent can access the parent-dom.
- allow-top-navigation: Do you want the guest to be able to replace the parent content completely?
- ms-allow-popups: Do you want the guest to be able to open popup windows?
An Example may look like this:
<iframe sandbox="allow-forms allow-same-origin"/>
Summary:
What to do when you have to use iframes and want to make it as secure as possible?
- Check the guest and the parent for persistent and reflective XSS/CSRF attacks
- Stick to transporting all content either via http or via https
- Use strickt sandbox rules