Clickjacking attack : All about Clickjacking


The Clickjacking attack allows to perform an action on victim site on visitor’s behalf.Many sites were hacked this way, including Twitter and Facebook (both fixed).

Click jacking

Clickjacking

The overall idea is simple.

  1. A visitor is lured to evil page. No matter how. “Click to get 1000000$” or whatever.
  2. The evil page puts a “get rich now” link with z-index=-1.
  3. The evil page includes a transparent iframe from the victim domain, say facebook.com and positions it so that “I like it” button is right over the link.

Here’s how it looks (half-transparent iframe for demo purposes):

Here’s how it looks (half-transparent iframe for demo purposes):

<!–
iframe { /* iframe from facebook.com */
width:300px;
height:100px;
position:absolute;
–>

top:0; left:0; filter:alpha(opacity=50); /* in real life opacity=0 */ opacity:0.5; }
Click on the link to get rich now:
 CLICK ME!
You’ll be rich for the whole life!

A click on the link actually happens on the iframe. Bingo! If the visitor is logged into facebook (and most of time he is), then facebook.com receives the click on behalf of the visitor.

On Twitter, it was the “Follow” button.

Same code, but transparent iframe (click to see the victim button pressed):

Actually, any single-click action is doable. All we need is to position the victim site iframe right. Most of time, the markup allows it.

Key events are much harder to hijack, because if the iframe is invisible, then the text in it’s input fields are invisible too. The visitor will start to type, but won’t see any text and won’t continue the action.

Defences and the ways to break through

The frame busting is a the good old framing protection technique. If you want to be sure that the document is not shown in iframe, you can add the following code to it:

// <![CDATA[
if(top != window) {
  top.location = window.location
}
// ]]>

So, in theory, if the current window is not the topmost, then top.location is changed, so it will be topmost.

But in real life, such protection is too weak. It can be challenged and beaten. There are many ways for it. Let’s review a few.

Blocking top navigation

It is possible to block the navigation caused by top.location assignment, in the onbeforeunload event.

The handler of this event returns a string which becomes a question to the user, asking him whether he wants to leave the page or not.

The outer window is located at the evil domain, so of course, the hacker may put any question there, and the user will believe and him stay. It’s always like that.

In the example below, there is a protected iframe with the code:

Changes top.location to google.com 

<script>
  top.location = 'http://google.com'
</script>
<input type="button" value="test" onclick="alert('button works')">

Here, the evil page cancels top location change with a smart onbeforeunload (the user should press cancel):

// <iframe src="http://javascript.info/files/tutorial/window/changetop.html" style="height:80px">

The event is not supported in Opera (at least Opera ⇐11) and ignored in this case by Chrome/Safari.

So the protection still works in Firefox and IE.

Other ways to workaround frame busting

  • In IE8, there is a proprietary security=”restricted” feature which forbids JavaScript in the frame.For example,
    
    
  • In Chrome (recent Webkit), we can use HTML5 sandbox attribute to allow scripts and forms, but forbid top navigation (no allow-top-navigation):So, iframe will be able to use scripts, but it may not change top.location.
  • Firefox and older IE can activate designMode in parent page, this also prevents frame busting (thanks to owasp.org clickjacking page for the idea).

There are other ways to evade the simple frame busting defence, not listed here. Browsers try to fix hacks, but new ways continue to emerge.

The reliable frame busting defence

The most reliable method is to suspend showing the document until the top == window check:

The code of the defending frame:

// <![CDATA[

  if (self == top) {
    var theBody = document.getElementsByTagName('body')[0]
    theBody.style.display = "block"
  } else { 
    top.location = self.location 
  }
// ]]>...

In the example above, we use document.getElementsByTagName('body') instead of document.body, because this way of getting BODY it works in all browsers when the document is not ready.

The only way to workaround it is HTML5 sandbox attribute which prevents top navigation. But newer browsers which support sandbox also provide another, even better way to protect from clickjacking (see below).

X-Frame-Options

All modern browsers support the X-Frame-Options header.

The header allows or disallows rendering of the document when inside an iframe.

It may have two possible values:

SAMEORIGIN
The document will be rendered (shown) in an frame only if the frame and it’s parent have the same origin.
DENY
The document may not be rendered inside a frame.

Browsers ignore the header if speicified in the META tag. So the following META will be ignored:

<meta http-equiv="X-Frame-Options" content="deny">

Demo

Let’s use the clickjacking demo example from the beginning of the article, but now the server adds X-Frame-Options="sameorigin" header.

In the code below, the iframe is half-transparent. Run it and note that the browser doesn’t render the iframe.

Click on the link below
CLICK ME!
You’ll be rich for the whole life!

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s