- Teo Selenius
- Follow @TeoSelenius
In this article, you will learn about clickjacking attacks, how they work, how they can put your website users at risk, and how you can prevent it.
What is Clickjacking?
Clickjacking attacks trick a website user to perform unwanted actions on a website unwittingly. It works by layering the target website in an invisible frame on a malicious website. When the user thinks they are clicking a button on the attacker's page, in reality, they click something on a completely different website.
Let's say we have a firewall administrator who is logged in at
What an attacker could do, is create a page like this. It tricks the user into clicking a button. In reality, the user would be disabling the firewall because the firewall management page is layered on top of the button in an iframe.
Of course, in a real attack, we wouldn't have any opacity so that the page would look like this:
The code of
https://evil.example could look (in a very simplified form) like this:
<div class="underlay"> <h1>WANT A MILLION DOLLARS?</h1> <button>CLICK ME</button> </div> <iframe class="invisible-overlay" src="https://firewall.example"></iframe>
A live demo
Here is a little web application. You can try it out right now. Click the button to enable and disable the firewall, but leave it turned on so that we can turn it back off with a clickjacking attack in a minute.
The attacker will create a page that shows a button "CLICK ME" and then overlays the target application on top of the button. Instead of clicking the "CLICK ME" button, the user will unwittingly click the "DISABLE" button on the firewall management page.
Here is the attacker page with a little bit of opacity to show how it works.
Here is the final attack, where the frame is entirely invisible. Try to click the button and then scroll back up to the firewall page. Observe how the firewall has been disabled.
Preventing clickjacking attacks
The only way to prevent clickjacking attacks is to block other websites from framing your website. There are a couple of ways to do this.
You can use the
X-Frame-Options HTTP response header to tell browsers not to frame your website at all.
Alternatively, you could only allow framing but only from your website.
X-Frame-Options cannot be used to allow specific websites to frame your website and is being obsoleted by
Content-Security-Policy. Read more here.
For details on
X-Frame-Options browser support see this page
Content-Security-Policy HTTP response header has a directive called
frame-ancestors which you can use to prevent the framing of your website.
Content-Security-Policy: ...other options... frame-ancestors 'none'
Or, just like with
X-Frame-Options you could allow your website to frame itself like so:
Content-Security-Policy: ...other options... frame-ancestors 'self'
The main benefit of using CSP instead of
X-Frame-Options is that you can also allow specific external websites to frame your website.
Content-Security-Policy: ...other options... frame-ancestors https://foo.example
Read more about CSP and
For up-to-date status of the browser support for
frame-ancestors, check this page.
The third way to prevent framing is to implement an isolation policy with fetch metadata headers. However, fetch metadata is not yet supported by all browsers. As such, you must also implement either
To implement an isolation policy that prevents framing:
- Create a middleware class that filters HTTP requests based on their headers.
- Based on the fetch metadata request headers, block requests that come from other websites.
- If you also want to block your website from framing itself, also block all navigation requests that are not destined to a document.
I understand this sounds a little bit abstract if you aren't familiar with fetch metadata headers. Here is an entire article about the topic with a complete example that you can run on CodeSandbox.
For up-to-date status of the browser support for fetch metadata headers, check this page.
Clickjacking attacks are a real threat to web applications. The only way to prevent them is not to allow other websites to frame your web application.
Luckily browsers enable us to do this. The most important defense is to deploy an
X-Frame-Options or a
Content-Security-Policy header that blocks framing.
You can achieve a nice additional defense layer by blocking requests to frames on the server-side by implementing an isolation policy with fetch metadata headers.