Wednesday, December 23, 2009

5 ways to prevent clickjacking on your website (and why they suck)

Clickjacking attack is a very nasty attack. The most common form of it is when an attacker creates a webpage and tricks the visitor to click somewhere (on a link, button, image). Attacker in the code of his website includes a victim website (like Facebook, your webmail, amazon) that is cleverly hidden from the user and placed so that a user actually clicks on a victim website. Citing the example from OWASP page on clickjacking:

For example, imagine an attacker who builds a web site that has a button on it that says "click here for a free iPod". However, on top of that web page, the attacker has loaded an iframe with your mail account, and lined up exactly the "delete all messages" button directly on top of the "free iPod" button. The victim tries to click on the "free iPod" button but instead actually clicked on the invisible "delete all messages" button. In essence, the attacker has "hijacked" the user's click, hence the name "Clickjacking".
The problem with clickjacking attack is that it is extremely difficult to prevent. Unlike other popular vulnerabilities like CSRF, XSS, SQL injection, this one is based on a functionality that is widely used in the web nowadays - frames (I'm skipping the case of plugin-based-clickjacking for clarity here). Frames allow you to nest one webpage or widget in another page - this is now used for login pages, commenting, previewing content in CMSes, for JavaScript interactions and a million other things.

Browsers nowadays use same origin policy to protect your data if you're framing or being framed from another domain (this prevents JavaScripts from talking to each other and accesing documents across the domain boundary). But JavaScript is not required for a clickjacking attack - CSS is enough. In the simplest form (e.g. used in recent Facebook users attack), you're just using a small <iframe>, and position it absolutely. The rest is just social engineering.

Our users have a few options to protect themselves. So maybe 1% of them will be "protected". But what can we - web developers do to prevent the clickjacking on our sites? Sadly, not much, but here's the list:


Include X-Frame-Options HTTP header in all your webpages. This will prevent your site from being placed within a frame. It's now supported by IE8, Safari 4, Google Chrome. Sadly, not Firefox.

+ extremely simple

- needs access to webserver configuration and/or scripting language on the server
- works only on some browsers
- no domain black/whitelisting (you either allow all, your domain only or none)

Framebuster JavaScript

You may also detect by JavaScript that your site is being placed in a frame and reload it main browser window (escape the hack). This is called frame-busting and it looks e.g. like this:

try {
if (top.location.hostname != self.location.hostname) throw 1;
} catch (e) {
top.location.href = self.location.href;

Sadly, it can be hacked. Luckily the hack can be hacked too, but there are so many caveats that you need to decide yourself. For example - your users won't see your site at all with JS disabled.
Notice: I've made some progress with this anti-frame-buster and came up with better solution but this one requires a proper demo and another blog post, so stay tuned.

+ you might code domain white/blacklisting yourself
+ you might alert() your users instead of escaping from frame

- requires JavaScript
- it's either hackable or requires significant workarounds on your website to make it work on all browsers

Move elements on your pages

The recent Facebook attack was possible because the Share link button was always placed in the same spot. When someone frames your site, he's "blind". Your browser knows where to render a button but it won't be possible for an attacker to check where this button is (nor will he be able to change CSS on your pages to modify how your site looks). 
If you e.g. position your button randomly (different spot on every page) - it just won't be where the attacker tricks the user to click.

- it's hard for your legitimate users (although you might move it only when you detect you're framed)
- the attacker might really do crazy things to hit your button eventually (e.g. a fake point and shoot game)

Require additional action

Require your users to mark a checkbox, fill in some password, solve a CAPTCHA in addition to clicking the button. This will make it harder for the clickjacker, as he now has to convince users to take more actions.

- hard for your legitimate users (although you might do it only when framed)
- it's still possible to trick users if the attackers tries hard enough

One-time URLs

The clickjacking attack is in a way similar to CSRF (when the user is on webpage A, he unwillingly does an action on website B), so the same prevention rules apply. To prepare the attack, clickjacker has to know two things:
  • your target URL (that URL will be framed)
  • where is the 'click area'
You may make the attack much much harder if you include a one-time code (nonce) in URLs to crucial pages. This is similar to nonces used to prevent CSRF but this time we're including nonces in URLs to target pages, not in forms within those pages.


<?php // my-account.php
$nonce = generate_nonce(); 
$_SESSION['nonce'] = $nonce; // store the generated nonce in session

// include it in URLs that you want to protect from clickjacking. 
// regenerate nonces on every page refresh.
<a href="<?php echo htmlspecialchars($nonce)?>">Delete my account</a>

<?php // delete-my-account-form.php
// ... 

// check if user came giving your correct one-time nonce. 

if ($_SESSION['nonce'] !== $_GET['nonce']) {
    return redirect_to('my_account.php'); // if not, direct him to previous page
    // you may also give an error message, log this etc. 
// ...

+ protects you also from CSRF

- this can't be used on URLs that need to be shared, bookmarked etc.
- users using browser tabs will get their pages expired


Sadly, there is no perfect solution for clickjacking protection yet. Given methods are not perfect, mostly because they affect your regular users (this also makes clickjacking similar to CSRF) and make it a bit harder for them to use your pages. What I would recommend is to use two methods simultaneously:
  • X-Frame-Options (for the future)
  • Detect if you're in frame, but don't escape from it (this can be prevented by clickjacker) but change your page instead (e.g. delete everything, disable buttons, require additional password, redirect to warning message) using JavaScript.
This way the majority of your users is protected, but all of them (even those without JavaScript) can still use your website.

If you want to read more about clickjacking and you're not afraid of technical jargon, I recommend this article.


warrioRR said...

I hate Clickjacking well this will help me out to Prevent ClickJacking thanks fot the Information

Rallport said...

LImiting post requests from your own domain is also good practice