X-Frame-Options or CSP frame-ancestors?

Posted on 02 April 2016 in misc

If you don't know about ClickJacking (UI Redressing) attack you can read the relevant article on OWASP website.

There are two main ways to prevent ClickJacking: frame breaking script and X-Frame-Options header (see RFC 7034). While first one is technologically flawed solution the second one is good enough in the most cases. Except situations when you need to give permission for framing your page to multiple sites. Since version 1.1 Content Security Policy has another ClickJacking defensive approach via frame-ancestors directive. Let's compare it with X-Frame-Options.

Basic (DENY and SAMEORIGIN) X-Frame-Options support in desktop browsers:

  • Google Chrome 4+
  • Internet Explorer 8+
  • Safari 4+
  • Mozilla Firefox 3.6+
  • Yandex.Browser

According to CSP2:

The 'none' source expression is roughly equivalent to that header’s DENY, 'self' to SAMEORIGIN, and so on. The major difference is that many user agents implement SAMEORIGIN such that it only matches against the top-level document’s location. This directive checks each ancestor. If any ancestor doesn’t match, the load is cancelled. The frame-ancestors directive obsoletes the X-Frame-Options header.

In following example framing of protected resource is only allowed for https://site1.com and https://site2.com

Content-Security-Policy: 
  frame-ancestors https://site1.com https://site2.com

frame-ancestors allows a website to authorize multiple domains using the normal CSP symantics (in contrast to X-Frame-Options, which allows only one) but be careful with it.

Also take into account that frame-ancestors does not fall back to the default sources when the directive is not defined (like form-action and base-uri). That is, such policy

Content-Security-Policy: 
  default-src 'none';

will still allow the resource to be framed from anywhere and you should explicitly specify frame-ancestors directive:

Content-Security-Policy: 
  default-src 'none';
  frame-ancestors 'none'

CSP frame-ancestors directive is supported in:

  • Google Chrome 40+
  • Mozilla Firefox 33+
  • Safari Technology Preview Release
  • Yandex.Browser

As you can see frame-ancestors is currently supported only in modern versions of major browsers :(

So, what solution to choose? Correct answer is to use them together. CSP is powerful protection (when it is correctly configured). X-Frame-Options is good for old browsers.