Clickjacking in JavaScript can compromise user actions. Explore effective prevention methods, including JavaScript frame busting and secure UI design.
A user lands on your page, sees a friendly button, and clicks it. Nothing looks wrong. But the click never went where they thought it did. It landed on an invisible layer stacked on top, and it just confirmed a payment or changed a setting on a completely different site. That is clickjacking, and the frustrating part is that the victim did everything right. They clicked what they saw. The attacker just made sure what they saw was a lie.
The word gets tied to JavaScript a lot, so let’s be honest up front: the reliable fix is not JavaScript. It’s a couple of HTTP response headers your server sends. We’ll cover how the attack works, the real defenses, and why the popular JavaScript trick is the weakest tool in the box.
Table of Contents
- What is Clickjacking?
- How Clickjacking Works in JavaScript
- Types of Clickjacking Attacks
- Real-World Examples of Clickjacking
- Preventing Clickjacking in JavaScript
- Conclusion
What is Clickjacking?
Clickjacking, sometimes called a “UI redress attack,” tricks someone into clicking a UI element they can’t actually see. The name is just “click” plus “hijacking.” An attacker loads your real site inside a frame, drops it behind decoy content, and lines up the invisible controls with the visible ones. The user reaches for the decoy and hits your live button underneath: authorizing a payment, liking a page, granting a permission, all without knowing it happened.
How Clickjacking Works in JavaScript
The mechanics are simpler than they sound. The attacker embeds your page in an iframe, sets its opacity to zero so it’s invisible, and positions a decoy button in the same spot. CSS handles most of the trick; JavaScript is only there to fine-tune positioning or follow the cursor. When the user clicks the decoy, the click passes through to your hidden page.
Clickjacking Example with a Hidden iframe
<!-- Attacker’s webpage -->
<div style="position: relative;">
<iframe src="https://trustedsite.com" style="opacity: 0; position: absolute; width: 100%; height: 100%;"></iframe>
<button style="z-index: 1;">Click Me!</button>
</div>The iframe pulls in a real site and sits invisibly over the visible button. The user clicks what looks like “Click Me!”, but the click registers inside the hidden frame instead. Notice one thing here: nothing in this attack reads your data directly. It steals a click, and the click does the damage.
Types of Clickjacking Attacks
Clickjacking shows up in a few shapes depending on what the attacker wants out of that stolen click.
1. UI Redressing Clickjacking
The classic version. A hidden frame or overlay sits over a visible button or link, and the user’s click triggers an action they never chose: submitting a form, changing a setting, sending data.
2. Likejacking
A social-media flavor of the same idea. An invisible “like” or “follow” control sits over something the user wants to click, and their click quietly boosts a page or post they never meant to endorse.
3. Cursorjacking
Here the attacker fakes the cursor. A custom cursor image is drawn at an offset from the real pointer, so the user aims at one thing and actually clicks another. It’s less common now that browsers are stricter about custom cursors, but it still turns up.
4. Nested Framing
A quick correction worth making: you’ll see “cookie theft via clickjacking” floating around, but that mixes up two different attacks. Because of the browser’s same-origin policy, the attacker’s page can’t read cookies or JavaScript inside your framed site. Reading data across origins is what cross-site scripting does, not clickjacking. What clickjacking can do is layer frames within frames to line up multi-step actions, so keep the two threats separate when you’re deciding what to defend against.
Real-World Examples of Clickjacking
This isn’t theoretical. A few well-known cases show the range.
1. Facebook Likejacking
The most famous wave hit Facebook around 2010 to 2011. Attackers embedded invisible “like” buttons on unrelated sites, and users clicking on ordinary-looking content ended up liking and spreading spam pages. It was widespread enough that Facebook added its own click-confirmation checks in response.
2. Payment and Confirmation Flows
Payment interfaces are a natural target, since one click can move money. Attacks have framed checkout or confirmation pages behind decoys to nudge users into approving a transaction they never saw.
3. Adobe Flash Settings (2008)
One of the earliest public demonstrations framed the Adobe Flash Player settings manager and tricked users into granting webcam and microphone access. It’s the case that put clickjacking on the map and pushed browsers and sites toward framing protections.
Preventing Clickjacking in JavaScript
Here’s the honest hierarchy. Clickjacking works because your page can be framed, so the real defense is telling browsers who is allowed to frame you. That happens in HTTP response headers, on the server, not in page JavaScript. Set these and most of the risk is gone.
1. Content-Security-Policy: frame-ancestors (your primary defense)
The frame-ancestors directive of the Content-Security-Policy header is the modern, standard way to control who can frame your page. It replaced the older header below and gives you finer control. Set it to 'self' to allow only your own origin, or list the specific origins you trust. Anything else gets blocked from framing you.
Content-Security-Policy: frame-ancestors 'self';2. X-Frame-Options (legacy fallback)
Before CSP Level 2, the X-Frame-Options header did this job. It still works in every major browser, so it’s worth sending alongside frame-ancestors as a backstop for anything old. Use DENY to block all framing or SAMEORIGIN to allow only your own site. Skip the old ALLOW-FROM value: both MDN and OWASP flag it as obsolete, and modern browsers ignore it entirely, which can leave you with no protection at all.
Header always set X-Frame-Options "SAMEORIGIN"3. JavaScript Frame Busting (weak, last resort)
This is the trick people reach for first, and it’s the one you should trust least. A frame-busting script checks whether the page is inside a frame and tries to break out of it.
if (window.self !== window.top) {
window.top.location = window.self.location;
}
The problem: an attacker frames you with a sandboxed iframe (<iframe sandbox>) that withholds the permission this script needs to navigate the top window, and the script silently does nothing. OWASP documents several other bypasses too. Treat frame busting as a courtesy for ancient browsers that don’t honor the headers, never as your actual defense.
4. Sensible UI Confirmation
Design can shrink the blast radius. Put a real confirmation step in front of anything destructive or irreversible, so a single stolen click can’t finish the job on its own. It won’t stop framing, but it raises the bar for turning a hijacked click into real damage.
Conclusion
Clickjacking is dangerous precisely because the user cooperates. They click what they see, and what they see is a decoy. The good news is that the fix is cheap and boring: send Content-Security-Policy: frame-ancestors to control who can frame you, add X-Frame-Options as a legacy backstop, and put a confirmation step in front of anything costly. Reach for JavaScript frame busting only when you have no other option, and know that a sandboxed iframe can switch it off. Set the headers, and most of this threat is closed before an attacker even starts.


