Iframe Breaking: How To Stop Unauthorized Iframing Of Your Content

A visitor to my site once informed me when he clicked on one of my links on Twitter; he was brought to my site with a big popup and a malicious code warning. That’s enough to scare the heck out of someone, so I started doing some testing. There was nothing wrong with my site – the problem was the link.
The link on another site produced a toolbar up top that encouraged people to click on a malicious link while loading my site in an iframe underneath. To most folks, my site could appear to be spreading malicious code. I wouldn’t say I like any site that loads my site within an iframe, so I did what any reasonable geek would do… I loaded up a frame breaker.
Iframing your site is not always malicious, though. We recently shared a tool, Sniply, to add a call-to-action (CTA) to any website link you share. It does this by embedding your entire site in an iframe and applying div over your content with the call-to-action.
But I’m pretty particular about my content and the effort I’ve put into Martech Zone, so I don’t want anyone to iframe my content, even with a link-share platform. In doing some research, there are quite a few ways to handle this.
How To Stop Iframing Your Content With JavaScript
This JavaScript code checks if the current window (self
) is not the top-most window (top
). If it’s not, this means the page is in a frame, iframe, or similar, and the script redirects the topmost window to the URL of the current window. This effectively breaks out of the iframe.
<script type='text/javascript'>
if (top !== self) top.location.href = self.location.href;
</script>
There are several downsides to this approach:
- Reliance on JavaScript: If the user has JavaScript disabled, this method won’t work.
- Delays: There can be a slight delay before the JavaScript executes, during which the framed version of your site could still be visible.
- Cross-Origin Restrictions: In some situations, the Same Origin Policy may prevent this script from working as intended. If the parent document is on a different domain, it might not be able to access
top.location.href
. - Potential for Frame-Busting-Busters: There are also scripts (called frame-busting-busters) that can prevent frame-busting scripts from working.
The better approach is to utilize HTTP response headers.
X-Frame-Options and Content-Security-Policy
Both X-Frame-Options
and Content-Security-Policy
(CSP) are HTTP response headers used to enhance the security of a website. They each serve slightly different purposes and have different levels of flexibility.
X-Frame-Options
is an older HTTP header specifically designed to control whether your site can be embedded in a <frame>
, <iframe>
, <embed>
, or <object>
on another site. It has three possible directives:
DENY
– The page cannot be displayed in a frame, regardless of the site attempting to do so.SAMEORIGIN
– The page can only be displayed in a frame on the same origin as the page itself.ALLOW-FROM uri
– The page can only be displayed in a frame on the specified origin.
However, X-Frame-Options
is limited in that it can’t handle more complex scenarios, like allowing framing from multiple different origins or using wildcards for subdomains. Not all browsers support the ALLOW-FROM
directive.
Content-Security-Policy
, on the other hand, is a much more flexible and powerful HTTP header. While it can do everything X-Frame-Options
can do and much more, its primary purpose is to prevent a wide range of code injection attacks, including cross-site scripting (XSS) and clickjacking. It works by specifying a whitelist of trusted sources of content (scripts, styles, images, etc.).
For controlling frames, CSP uses the frame-ancestors
directive. You can specify multiple sources, including multiple domains and wildcard subdomains. Here’s an example:
cssCopy codeContent-Security-Policy: frame-ancestors 'self' yourdomain.com *.domain2.com;
This would allow the page to be framed on its own site ('self'
), on yourdomain.com
, and on any subdomain of domain2.com
.
CSP is being recommended as a replacement for X-Frame-Options
, since it can handle everything X-Frame-Options
can do, and much more. While most modern browsers support CSP, there might still be some old or less common browsers that do not fully support it.
How To Stop Iframing Your Content With HTML
There is now a Content-Security-Policy meta tag that can be deployed that disables the ability to iframe your content:
<meta http-equiv="Content-Security-Policy" content="frame-ancestors 'self' yourdomain.com">
The effectiveness of the HTML meta tag is limited because not all browsers respect the Content-Security-Policy
when set using a meta tag.
How To Stop Iframing Your Content With HTTP Headers
It’s better to use the HTTP headers X-Frame-Options
or Content-Security-Policy
to control framing. These options are more reliable, and secure, and work even if JavaScript is disabled. The JavaScript method should only be used as a last resort if you don’t have control over the server to set HTTP headers. For each example, replace yourdomain.com
with your actual domain.
Apache – Modify your .htaccess
file as follows:
Header always set X-Frame-Options SAMEORIGIN
Header always set Content-Security-Policy "frame-ancestors 'self' yourdomain.com"
Nginx – Modify your server block as follows:
add_header X-Frame-Options SAMEORIGIN;
add_header Content-Security-Policy "frame-ancestors 'self' yourdomain.com";
IIS – do this by adding the following to your web.config
file:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Content-Security-Policy" value="frame-ancestors 'self' yourdomain.com" />
</customHeaders>
</httpProtocol>
</system.webServer>
WordPress – do this by adding this code to your functions.php file:
function add_security_headers() {
header('X-Frame-Options: SAMEORIGIN');
header("Content-Security-Policy: frame-ancestors 'self' yourdomain.com");
}
add_action('send_headers', 'add_security_headers');
These configurations will only allow your page to be embedded within iframes on the exact domain you specify, not on any domain subdomains. If you want to allow certain subdomains, you’ll have to list them explicitly, like subdomain1.yourdomain.com
subdomain2.yourdomain.com
, and so on.
Allow Iframing Your Content From Multiple Domains
You can specify multiple domains with the Content-Security-Policy HTTP response header and the frame-ancestors directive. A space should separate each domain. Here’s an example:
Content-Security-Policy: frame-ancestors 'self' domain1.com domain2.com domain3.com;
Apache – Modify your .htaccess
file as follows:
Header always set X-Frame-Options SAMEORIGIN
Header always set Content-Security-Policy "frame-ancestors 'self' domain1.com domain2.com domain3.com"
Nginx – Modify your server block as follows:
add_header X-Frame-Options SAMEORIGIN;
add_header Content-Security-Policy "frame-ancestors 'self' domain1.com domain2.com domain3.com";
IIS – do this by adding the following to your web.config
file:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="Content-Security-Policy" value="frame-ancestors 'self' domain1.com domain2.com domain3.com" />
</customHeaders>
</httpProtocol>
</system.webServer>
Allow Iframing Your Content From A Wildcard Domain
You can also specify a wildcard for all subdomains with the Content-Security-Policy
HTTP response header and the frame-ancestors directive. Here are examples of the Content-Security-Policy
code that needs to be updated:
Content-Security-Policy: frame-ancestors 'self' *.yourdomain.com;
Apache – Modify your .htaccess
file as follows:
Header always set Content-Security-Policy "frame-ancestors 'self' *.yourdomain.com"
Nginx – Modify your server block as follows:
add_header Content-Security-Policy "frame-ancestors 'self' *.domain1.com *.domain2.com *.domain3.com";
IIS – do this by adding the following to your web.config
file:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Content-Security-Policy" value="frame-ancestors 'self' *.yourdomain.com" />
</customHeaders>
</httpProtocol>
</system.webServer>