var self = justin();

Software Developer Teammate

A place to remind my future self of what I've learned and experienced. That means both my successes and failures.


Click Jacking

TL;DR

Scroll down to the bottom for a github repo and a list of links to see the code in action.

It's pretty slick

I get a little too excited, and paranoid, when I think about different types of attacks hackers can utilize against web sites. One of the ones I find more clever is the click jacking attack. In a nutshell, a hacker loads your page in an iframe and the positions elements on top of your page. The victim then startsto interact with the hacker's elements while the victim believes they are clicking on your site.

The Example

Imagine this simple scenario: you have a simple login form with user id, password and a button that submits the credentials to the server. Now, an attacker loads this login page inside of an iframe. He then positions a similiarly styled user id and password input directly over the ones on your page. On blur, the attacker submits that data via JSONP calls to their server and then attempts to hack the victim's account. Yeah, pretty cool, right?

There are two canonical ways of dealing with this attack and they are both too simple not to do.

X-Frame-Options

The first is simply adding the X-Frame-Options http header to your responses. In every framework I've worked with, it's be trivial to do this. In a .NET MVC app, just add the following to your web.config:

<system.webServer>
    <httpProtocol>
          <customHeaders>
            <add name="X-Frame-Options" value="DENY"/>
          </customHeaders>
    </httpProtocol>
</system.webServer>

X-Frame-Options lets the browser know about any restrictions the site has on being loaded inside of an iframe. For example, DENY says "Thou shalt not load me under thine iframe". On a side note, the spec for the header was written in the King James version of the Bible. You can also use the option SAMEORIGIN which just means "I can only be loaded in an iframe if that iframe resides on a page that is from my same domain."

This is easy to do but isn't full proof because of two reasons:

  • You have no control over any proxies down the line. It is possible that a proxy will strip headers for what ever reason.
  • Internet Explorer 7

So, what else can you do to help ensure that your page can't be loaded from an iframe? How about a little JavaScript goodness?

JavaScript Frame Busting

Stanford Web Security Research came up with a clever option of defending against click jacking.

The first step is to add a style in the head of the document that hides the body.

<style id="antiClickjack">body{display:none !important;}</style>

Then, add some JavaScript (still in the head) that checks to see if the page was loaded in an iframe. If it wasn't, then remove the previously added style. If it was loaded via an iframe, then redirect the next top frame (either the window or a parent iframe) to the real page.

<script type="text/javascript">
    if (self === top) {
        var antiClickjack = document.getElementById("antiClickjack");
        antiClickjack.parentNode.removeChild(antiClickjack);
    } else {
        top.location = self.location;
    }
</script>

Now, you may be asking yourself "Self, why does this technique hide the body? If the page is in an iframe, then the page will be redirected no matter what." To which your 'self' would reply "Because attackers could take advantage of the XSS filters in Chrome in IE and prevent any JavaScript from running within the iframe. This way, if that happens, at least the page won't be visible."

Then you would tell yourself "oh, right... XSS filters. Of course"

Url Referrer

I know I said there were two canonical ways, but there is a helper way that the tin foil hat guys could employ. Checking the url referrer to ensure it matches a list of domains that could possibly be requesting the iframe (or making sure it only comes from your domain) would help mitigate the attack but this poses some problems. Proxies, browser plugins and ad-ware/mal-ware all can remove the url referrer or make it blank.

I mention it because I generally add this form of protection to help prevent CSRF attacks, but it is not without its flaws.

See it in action

To demonstrate the first two options, I created one of the free websites in Azure and put up a login form.

  • Here's the standard login form.
  • Here's the login formed loaded via an iframe. You'll get a popup when you enter information into the text boxes. In this page, I've absolutely positioned some text boxes on top of the boxes in the iframe's content. Then I added some JavaScript that would siphon away the data off to some evil.com site.
  • Here's the defense using the X-Frame-Options header. Open up your network tab and look at the response headers. You'll see that it says 'DENY'. Also, most browsers will print to the console the fact that iframe's content was not rendered.
  • Here's the JavaScript defense. The project is subtle, but you'll notice that you are redirected from /home/javascript to /home/javascriptprotection. This happened because the script on the login page detected it was being loaded from an iframe.

The Code

Lastly, here's the github repo with the code.

comments powered by Disqus