mylk Mylk's blog

Avoid clickjacking or how to manage framing

There may be some times where you would need to:

  • deny embedding your web application into other websites
  • allow a website to embed your web application

The first one is also known as protection from “clickjacking”.

Clickjacking is tricking users into clicking something seemingly harmless and different from what they think they click on, in order to reveal confidential information or infect them.

Embedding your web application into a 3rd party website all about someone using either a <frame>, <iframe> or <object> HTML tag to include your content into his website.

#

How to avoid clickjacking

There are a couple of ways to fight against clickjacking:

  • use the appropriate HTTP headers,
  • “frame-busting” JavaScripts

JavaScript is not the solution

Using JavaScript to prevent being “framed” is really popular, but be careful about depending on it. The “restricted zones” give the ability to disable JavaScript in the context of a frame, turning the frame-busting code useless.

Some examples of how to disable JavaScript on iframes:

On Chrome:

<iframe src="http://www.example.com" sandbox></iframe>

On IE:

<iframe src="http://www.example.com" security="restricted"></iframe>

On Firefox (works on IE too) the parent page (the page that frames you) has to just enable the “design mode”.

document.designMode = "on";

I would suggest not to depend on frame-busting with JavaScript.

#

The HTTP headers way

Using HTTP response headers is the most reliable way. The headers tell the browser that embedding a page of yours into another page is not permitted.

The appropriate header to deny framing:

X-Frame-Options: DENY

The DENY option, will even prevent your own web application to frame your web application.

#

Manage framing

There may be a case where you want your web application / website to be framed but only into a specific website.

Use the header that fits your case:

X-Frame-Options: SAMEORIGIN

X-Frame-Options: ALLOW-FROM https://example.com/

With SAMEORIGIN only your own web application can frame your web application and with ALLOW-FROM only the defined page can frame your web application.

#

Setting-up X-Frame-Options

The X-Frame-Options header will not work if you just place it on an HTML <meta> tag.

One way to set it up is to manually send the header on every response, but the most simple way is to configure your webserver to do so.

Also, its really possible that your PHP framework may give you the ability to send the header by just configuring the framework, so you won’t need to touch your webserver configuration at all.

#

Limitations of X-Frame-Options

The ALLOW-FROM option is relatively recent and may not be supported by all browsers. So, if the visitor’s browser doesn’t support it, you don’t provide any clickjacking protection to that visitor.

Something else disturbing is that there is no straight-forward way to add multiple origins to ALLOW-FROM. Just one X-Frame-Options header is allowed and can have only one value on the ALLOW-FROM directive. So, you will need some programming juggling there.

Last but not least, even while X-Frame-Options is the established way of managing framing and being supported by the majority of browsers, it was never standardized and is being deprecated in favour of theframe-ancestors directive.

#

The frame-ancestors directive

frame-ancestors is a directive of the Content-Security-Policy (CSP) header.

To deny framing by all origins:

Content-Security-Policy: frame-ancestors 'none'

To allow framing from your origin only:

Content-Security-Policy: frame-ancestors 'self'

To allow only a single website to frame you:

Content-Security-Policy: frame-ancestors example.com

What’s nice is that frame-ancestors allows you to define multiple origins by separating them with spaces.

#

Limitations of CSP

The browser support of the frame-ancestors is still limited (2016 Q4).

Also, if you send both X-Frame-Options and frame-ancestors, some browsers will give priority to X-Frame-Options, even if the standard says that X-Frame-Options has to be ignored if the frame-ancestors directive is defined.

Note that neither CSP will work if is set in an HTML <meta> tag.