A clickjacking attack allows a malicious page to click on a victim site on behalf of the visitor.
Many sites have been hacked in this manner, including Twitter, Facebook, Paypal and others. All of them, of course, are now protected.
The idea behind this attack is very simple.
Here's how the clickjacking attack was carried out on Facebook:
- The visitor is lured to a malicious page (no matter how).
- There is a link on the page that looks harmless (for example, “Get Rich Now” or “Click Here, It’s Very Funny”).
- On top of this link, the malicious page places a transparent
iframewith thesrcfrom the facebook.com website in such a way that the “like” button is located directly above this link. This is usually done using z-index in CSS. - When attempting to click on this link, the visitor actually clicks on a button.
This is what the malicious page code looks like. For clarity, the iframe is semi-transparent (on real malicious pages it is completely transparent):
<-style->
iframe { /*-- iframe from the victim site --*/
width: 400px;
height: 100px;
position: absolute;
top:0; left:-20px;
opacity: 0.5; /*-- in real case opacity:0 --*/
z-index: 1;
}
<-/style->
<-div->Click here to get rich:<-/div->
--- Url iframe from the victim site ---
<-iframe src="/clickjacking/facebook.html"-><-/iframe->
<-button->Click here!<-/button->
---...And everything will be great (for me, a hacker)!---
Here we have a semi-transparent
iframe src="facebook.html", and in the example we see it hanging over the button. Clicking the button actually clicks on the iframe, but this is not visible to the user because the iframe is transparent.As a result, if the user is logged in to the Facebook website (“Remember me” is usually activated), then he adds a “like”. On Twitter this will be the “read” button, etc.
All we need for the attack is to position the
iframe on the malicious page so that the button is directly above the link. So the user clicking the link will actually be clicking a button in the iframe. This can usually be done using CSS positioning.
Clickjacking attack is good only for mouse clicks, not keyboard
This attack only works on mouse actions (or similar ones, such as finger clicking on a mobile device).
Keyboard input is much more difficult to redirect. Technically, if we have a textbox to hack, we can arrange the iframe so that the textboxes overlap each other. Then the visitor, when trying to focus on the text field that he sees on the page, will actually focus on the text field inside the iframe.
But there is one problem. Anything the visitor types will be hidden because the iframe is not visible.
People usually stop typing when they don't see new characters on the screen.
The oldest protection option is JavaScript code that prevents the page from opening in a frame (this is called “framebusting”).
It looks like this:
if (top != window) {
top.location = window.location;
}
In this case, if a window detects that it is open in a frame, it automatically positions itself on top. This method is not a reliable protection, since many ways to bypass it have appeared. Let's look at some of them.
One of the things restricted by the sandbox attribute is navigation. A sandboxed iframe may not change top.location.
So we can add the iframe with sandbox="allow-scripts allow-forms". That would relax the restrictions, permitting scripts and forms. But we omit allow-top-navigation so that changing top.location is forbidden.
Here’s the code:
<-iframe sandbox="allow-scripts allow-forms" src="facebook.html"-><-/iframe->There are other ways to work around that simple protection too.
The server-side header X-Frame-Options can permit or forbid displaying the page inside a frame.
It must be sent exactly as HTTP-header: the browser will ignore it if found in HTML tag. So, <-meta http-equiv="X-Frame-Options"...-> won’t do anything.
The header may have 3 values:
DENY
Never ever show the page inside a frame.
SAMEORIGIN
Allow inside a frame if the parent document comes from the same origin.
ALLOW-FROM domain
Allow inside a frame if the parent document is from the given domain.
For instance, Twitter uses X-Frame-Options: SAMEORIGIN.
The X-Frame-Options header has a side effect. Other sites won’t be able to show our page in a frame, even if they have good reasons to do so.
So there are other solutions… For instance, we can “cover” the page with a <-div-> with styles height: 100%; width: 100%;, so that it will intercept all clicks. That <-div-> is to be removed if window == top or if we figure out that we don’t need the protection.
Something like this:
<-style->
#protector {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 99999999;
}
<-/style->
<-div id="protector"->
<-a href="/" target="_blank"->Go to the site<-/a->
<-/div->
<-script->
// there will be an error if top window is from the different origin
// but that's ok here
if (top.document.domain == document.domain) {
protector.remove();
}
<-/script->
The samesite cookie attribute can also prevent clickjacking attacks.
A cookie with such attribute is only sent to a website if it’s opened directly, not via a frame, or otherwise.
If the site, such as Facebook, had samesite attribute on its authentication cookie, like this:
Set-Cookie: authorization=secret; samesite…Then such cookie wouldn’t be sent when Facebook is open in iframe from another site. So the attack would fail.
The
samesite cookie attribute will not have an effect when cookies are not used. This may allow other websites to easily show our public, unauthenticated pages in iframes.However, this may also allow clickjacking attacks to work in a few limited cases. An anonymous polling website that prevents duplicate voting by checking IP addresses, for example, would still be vulnerable to clickjacking because it does not authenticate users using cookies.
Clickjacking is a way to “trick” users into clicking on a victim site without even knowing what’s happening. That’s dangerous if there are important click-activated actions.
A hacker can post a link to their evil page in a message, or lure visitors to their page by some other means. There are many variations.
From one perspective – the attack is “not deep”: all a hacker is doing is intercepting a single click. But from another perspective, if the hacker knows that after the click another control will appear, then they may use cunning messages to coerce the user into clicking on them as well.
The attack is quite dangerous, because when we engineer the UI we usually don’t anticipate that a hacker may click on behalf of the visitor. So vulnerabilities can be found in totally unexpected places.
- It is recommended to use
X-Frame-Options: SAMEORIGINon pages (or whole websites) which are not intended to be viewed inside frames. - Use a covering
<-div->if we want to allow our pages to be shown in iframes, but still stay safe.
Documentation compiled using information from https://javascript.info/clickjacking