What do you know about Clickjacking?
Clickjacking, also known as a “UI redress attack”, is an attack vector where multiple transparent or opaque layers are used to trick a user into clicking on a button or link on different page than visually seen by the user. Thus, the attacker is “hijacking” clicks meant for your page and routing them to another page for various reasons.
Using a similar technique, keystrokes can also be hijacked. With a carefully crafted combination of stylesheets, iframes, and text boxes, a user can be led to believe they are typing in the password to their email or bank account, but are instead typing into an invisible frame controlled by the attacker.

On the example above, you can see how a clickjacking attack works. The user is shown a trap website with a snare button — the button is made to look attractive for the user to click on. However, in reality an invisible iframe is positioned on top of the button in such a manner that the target buttons are aligned.
In this example it is an account delete button from another website (if the user is logged in on that site, then the iframe will properly render the button in the right location). So instead of clicking on the supposed “Win”, they will instead click on the “Delete” button.
This is a simplified example of the attack, but it can be used to do a lot of damage depending on the target.
The more famous examples of clickjacking include Twitter and Facebook worms that surfaced around 2010 and 2011. These clickjacking attacks used the user’s click to add the malicious URL to their social media. This in turn would attract more users to click the link and so it propagated fast throughout the user base.
Mitigate the attack vector
Clickjacking is a product of clever UI modifications using your site’s content in an iframe. So in order to defeat the attack vector you must not allow your site to be used inside an iframe except in a manner you specify.
A regular website has little use cases where they should allow their website inside an iframe. That is why zero tolerance is usually a good way to go. There are some cases where you would want specific pages to be usable in an iframe — widget inclusion and such — and therefore require lifting the zero tolerance for those specific instances.
How to achieve this?
Browser vendors, fortunately being fully aware of the dangers of this, have implemented X-Frame-Options and Content-Security-Policy headers, which we can be used to prevent framing our website.
You might be wondering why there are two different headers for this purpose. Well the X-Frame-Options, which is more supported across the various browser vendors, was never actually standardised. In contrast, the new Content-Security-Policy (CSP) is a standardised header meant for mitigating various content related security issues. Unfortunately it is not yet fully supported by all browsers.
When you expect users with older browser versions to visit your site, then there is also a third option called frame-busting, which is a combination of CSS and JS designed to inhibit framing your website.
We will look at all three methods in turn.
X-Frame-Options
The X-Frame-Options is currently the best vendor supported solution against clickjacking attacks.
There are three possible values for X-Frame-Options:
- 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 of the same origin as the page itself.
- ALLOW-FROM uri The page can only be displayed in a frame on the specified origin.
The ALLOW-FROM option has limited support and is therefore not recommended. Instead, use one of the other two options. Because X-Frame-Options header has no method to define the pages where it applies, then you will have to handle this part yourself. That usually involves setting it by default and removing it only on the pages you require to work inside an iframe.
For a zero tolerance (which is usually what you need) I would set up a middleware high up the stack if using express
app.use(function applyXFrame(req, res, next) {
res.set('X-Frame-Options', 'DENY');
next();
});
Or if you are using a proxy server like Nginx in front of your Node.js application, then you can set it there:
add_header X-Frame-Options DENY;
When you do have routes that have to work inside frames, then you will either have to set the header on all routes that are not allowed, or if possible, set the header for all routes and remove where needed, by setting it to empty.
Content-Security-Policy
The Content-Security-Policy header is a new standardised header for specifying content related policy. This includes the frame-ancestors directive that is used to prevent clickjacking attacks.
The frame-ancestors takes a source-list of allowed parents as an argument. You can use the following built in keywords:
- ‘none’ Roughly equals to X-Frame-Options DENY;
- ‘self’ Roughly equals to X-Frame-Options SAMEORIGIN;
Or directly specify the URLs that can frame the site.
Implementation is very similar to the X-Frame-Options. Set the header as broadly as possible in your application stack:
app.use(function applyCSP(req, res, next) {
res.set('Content-Security-Policy', "frame-ancestors 'none';");
next();
});
The problem with CSP header is that the support for frame ancestors and CSP is very limited — only the newest version of Chrome, Firefox and Opera have actual support. However, because CSP is a standardised header, we can expect to see the X-Frame-Options die out and be replaced by CSP as browser vendors catch up.
Frame-busting
Because the support for the X-Frame-Options and Content-Security-Policy headers is not yet complete, there exists a third option called frame-busting. It involves using a combination of CSS and JavaScript to stop the website from being included in frames.
More specifically, it means including the following block in the head part of the html document:
<style id="antiClickjack">body{display:none !important;}</style> <script type="text/javascript">
if (self === top) {
var antiClickjack = document.getElementById("antiClickjack");
antiClickjack.parentNode.removeChild(antiClickjack);
} else {
top.location = self.location;
}
</script>
Let’s analyse a bit what this code does:
- It forces the display:none; on the whole body.
- It uses JavaScript to check if the current window is the topmost window element (global variable self references the current window and top refers to the top window).
- If the top window is the current window then the display:none; is removed.
With this code, the content loading will not be stopped in the framed page. Instead, the content will not be shown and therefore the user won’t be able to interact with the page.
The frame-busting solution is the most reliable of the three available options, because it doesn’t rely on the browsers support. However, on the downside, your site will become unusable for people who have JavaScript disabled.
Wrapping it up
Clickjacking or UI redress attack is an attack vector designed to steal a user’s click by covering the intended click area with an invisible frame that is housing a different action. It can also be used to target input elements with the aim of hiding the true input from the user.
Defending against this attack vector means controlling which parts of the web application can appear inside frames. It boils down to three choices — using a Content-Security-Policy header, an X-Frame-Options header or using CSS and JavaScript in what is known as frame-busting. The first two rely on the browser’s security implementations to achieve the result, while the third is applicable even with old browsers.
Taking this into account, I would recommend using both of the headers if you do not plan to support older browsers or want to allow scriptless browsing of your application.
If indeed your target audience is likely to have older browsers then frame-busting is much more universally functional and should be the prime choice.
This was part two of the Node.js Web Application Security Series focusing on various web application security topics and how they can be mitigated in Node.js applications.
Sufficient knowledge about web security is something every decent developer should know. Even if you are not security oriented, this knowledge will be useful for designing more robust and secure systems. This in turn makes you a better developer overall.
If you find these mini tutorials useful, I recommend that you buy and read my book “Secure Your Node.js Web Application: Keep Attackers Out And Users Happy”. The book provides more in depth and practical knowledge about Web Application Security and implementing security mechanisms in Node.js applications.
Originally published at nodeswat.com on January 27, 2016.