Clickjacking is a web attack where a user is deceived into clicking on a webpage element that is either invisible or disguised as another element. An attacker achieves this by loading the target website within a transparent iframe and layering it over a seemingly harmless page. The user believes they are clicking a button on the visible page, but they are actually interacting with the hidden page. For example, a user might see a “Play Game” button, but their click is registered on a “Delete Account” button within the invisible iframe loaded from a different site.
This attack exploits a user’s active session on the target website. If a user is logged into their bank, social media, or email, an attacker can trick them into performing actions on that site without their consent. The potential actions are broad, from transferring funds and changing passwords to spreading malware or liking a social media page. The attack’s effectiveness comes from the fact that the actions are performed by the user’s browser, making them appear legitimate to the target server.
Modern browsers have built-in protections, yet clickjacking persists as a major security issue. Vulnerabilities often arise from server misconfigurations or a lack of proper security headers. As web applications grow and integrate more third-party services, new opportunities for this type of attack can emerge. A correctly configured defense is an important part of a website’s security.
How Clickjacking Attacks Work: A Technical Breakdown
A clickjacking attack follows a clear sequence of steps to hijack a user’s actions. The core technique involves layering an invisible, legitimate website over a visible, malicious one.
- Attacker’s Webpage: An attacker first creates a webpage containing a decoy element, such as a button or link, designed to attract a user’s click. This is the only part of the setup the user will consciously see.
- Target iFrame: The attacker then embeds the target website—for instance, a user’s bank account page or social media profile—into an <iframe> on their own page. For the attack to work, the user must have an active session on the target website.
- CSS Manipulation: The attacker applies CSS properties to manipulate the iframe. The opacity is set to 0 to make it completely transparent. The z-index is set to a high value, placing the invisible iframe on a layer above the decoy content. The iframe’s position is then adjusted so that a specific, actionable element on the target page (like a “Confirm Transfer” button) aligns perfectly over the decoy button on the attacker’s page.
- User Interaction: A user visits the attacker’s page and sees the decoy content. When they click the decoy button, their action passes through the transparent layer. The click is registered by the aligned button on the hidden target website. The browser sends this request to the target server with the user’s cookies, making the action appear legitimate.
Here is a simplified code example showing the structure:
<!– Attacker’s Page –>
<body>
<!– The decoy button the user sees –>
<button style=”position: absolute; z-index: 1;”>
Click for a Free Prize!
</button>
<!– The invisible iframe with the target site –>
<iframe
src=”http://target-website.com/action_page”
style=”
position: absolute;
width: 200px; /* Dimensions of the target button */
height: 50px;
opacity: 0; /* Makes the iframe invisible */
z-index: 2; /* Places it on top of the decoy */
“>
</iframe>
</body>
In this structure, the iframe is positioned so its internal “Confirm” button is directly under the user’s cursor when they go to click the “Free Prize” button.
Server-Side Defenses: X-Frame-Options and Content Security Policy
The most effective way to stop clickjacking is by instructing the browser on how it should handle framing of your website’s pages. This is done through HTTP response headers sent from your server. There are two major headers for this purpose: X-Frame-Options and the frame-ancestors directive of Content Security Policy (CSP).
X-Frame-Options
X-Frame-Options is a widely supported HTTP header that provides a direct way to control if your site can be embedded in an <iframe>, <frame>, <embed>, or <object>. It has three possible directives:
- DENY: This directive completely prevents any site from loading the page in a frame. This is the most restrictive and secure option.
- X-Frame-Options: DENY
- SAMEORIGIN: This directive allows the page to be framed, but only by pages from the same origin. For example, your-site.com can frame another page from your-site.com.
- X-Frame-Options: SAMEORIGIN
- ALLOW-FROM uri: This directive was intended to permit a specific URI to frame the page. Support for it is inconsistent across browsers, and it has been made obsolete by CSP. Using it is not recommended.
Content Security Policy (CSP): The frame-ancestors Directive
Content Security Policy is a more modern and highly flexible security standard. The frame-ancestors directive within a CSP header is the current recommended method for controlling embedding. It replaces the older X-Frame-Options header.
The frame-ancestors directive specifies the parent pages that may embed the current page. Its values offer more control:
- ‘none’: Prevents any domain from framing the content. This is functionally the same as X-Frame-Options: DENY.
- Content-Security-Policy: frame-ancestors ‘none’;
- ‘self’: Allows the content to be framed only by pages from the same origin. This is functionally the same as X-Frame-Options: SAMEORIGIN.
- Content-Security-Policy: frame-ancestors ‘self’;
- <source>: You can specify one or more sources (domains) that are permitted to frame the page. This is a major advantage over X-Frame-Options, as you can whitelist multiple trusted domains.
- Content-Security-Policy: frame-ancestors https://trusted-partner.com https://another-trusted-site.com;
If both X-Frame-Options and a CSP with frame-ancestors are present, modern browsers will give precedence to frame-ancestors. It is still a good practice to send both headers. This provides protection for users on older browsers that do not support CSP but do support X-Frame-Options. You can use a CSP Policy Builder to generate the correct header syntax for your needs and an iFrame Tester to verify their implementation.
Client-Side Countermeasures: The Rise and Fall of Frame-Busting JavaScript
Before server-side headers became the standard, developers used client-side JavaScript for protection against clickjacking. This technique, known as “frame-busting” or “frame-breaking,” involves adding a script to a webpage that detects if it is being loaded inside a frame. If it finds itself in a frame, the script attempts to take over the top-level window and redirect it to its own URL.
A basic frame-busting script looks like this:
<script>
if (top.location !== self.location) {
top.location = self.location;
}
</script>
This code compares the location of the top-level window (top.location) with its own location (self.location). If they are different, it indicates the page is framed, and the script tries to force the main browser window to navigate to the page’s actual URL, thereby “busting out” of the frame.
This method, however, is no longer a reliable defense. Attackers developed their own scripts to defeat these countermeasures. A common technique involves using the onbeforeunload event handler on the attacker’s page. This event fires just before the page is about to be unloaded.
An attacker can set up their page to cancel the redirect initiated by the frame-busting script. The attacker’s page can register an onbeforeunload event that returns a message to the user, effectively preventing the navigation.
Another major weakness involves the sandbox attribute of an <iframe>. An attacker can embed the target site in a sandboxed iframe without granting the allow-top-navigation permission. This browser-level restriction completely blocks the framed page’s script from being able to change the top.location, rendering the frame-busting code useless.
Because these client-side scripts can be circumvented, they are considered an insufficient protection against clickjacking. The use of HTTP headers like Content-Security-Policy and X-Frame-Options provides a much more secure and dependable solution managed by the browser itself.
Modern Browser Security Features that Mitigate Clickjacking
In addition to enforcing server-sent headers, modern browsers have implemented other security mechanisms that make clickjacking more difficult to execute. A major development in this area is the SameSite attribute for cookies.
The SameSite cookie attribute allows a server to control when a user’s cookies are sent with requests initiated from external websites. This is an important defense because a clickjacking attack relies on the browser automatically including the user’s session cookie with the deceptive click. The attribute has two primary settings that help stop this:
- SameSite=Strict: When a cookie is set with this value, the browser will not send it with any cross-site requests. This means if a user is on attacker.com and clicks a hidden button that sends a request to your-bank.com, the session cookie for your-bank.com will be withheld. The request will fail because the bank’s server will not be able to identify the user. This setting offers a very strong defense against clickjacking.
- SameSite=Lax: This is the default setting in many modern browsers. It is a balance between security and usability. Cookies with Lax are not sent on cross-site subrequests, such as those made to load images or frames, and they are withheld on cross-site POST requests. They are, however, sent when a user navigates to the URL from an external site (for example, by clicking a link). This default behavior is effective at stopping many forms of clickjacking that rely on submitting data via POST requests.
Another security principle that plays a role is the Same-Origin Policy (SOP). The SOP prevents a script on one webpage from accessing the data or properties of a page from a different origin. In a clickjacking scenario, this means the attacker’s page cannot read the content of the transparent iframe. It cannot see the user’s account balance or read personal information. The SOP limits the attacker to “blind” clicks on known button locations.
These browser-level features provide a sizeable layer of protection. Still, they are intended to work as part of a defense-in-depth strategy. Relying on them alone is not a suitable security posture. The most direct and explicit way to prevent your site from being framed is by using the Content-Security-Policy: frame-ancestors and X-Frame-Options headers.
A Practical Checklist for Auditing Your Website’s Vulnerability
To determine if your website is properly defended against clickjacking, you can perform a direct audit of its configuration and security features. This checklist covers the major areas to inspect.
- Examine HTTP Response Headers The most important step is to check the headers your server sends. Open your browser’s developer tools, select the Network tab, and load a page from your website. Click on the main document request to view the response headers. Look for X-Frame-Options and Content-Security-Policy.
- An X-Frame-Options header should be present with a value of DENY or SAMEORIGIN.
- A Content-Security-Policy header should contain a frame-ancestors directive set to ‘none’ or ‘self’.
- The absence of both headers indicates a vulnerability. A simple way to get a clear result is to use an iFrame Tester. This tool gives you immediate visual confirmation of whether a page can be embedded, showing exactly how a browser will enforce your security headers.
- Inspect Session Cookie Attributes The SameSite attribute on your session cookies provides another layer of defense. In your browser’s developer tools, go to the Application (or Storage) tab and inspect the cookies for your domain. Your primary session cookie should have its SameSite attribute set to Lax or Strict. This setting prevents the browser from sending the cookie with most cross-site requests, which is how a clickjacking attack hijacks a user’s session.
- Review State-Changing Forms Audit any forms that perform sensitive actions, such as changing a password, submitting personal information, or making a purchase. These forms should be protected with anti-CSRF (Cross-Site Request Forgery) tokens. While CSRF is a different type of attack, strong anti-CSRF measures can also neutralize the impact of a click on a hijacked form.
- Remove Legacy Frame-Busting Scripts If your codebase is older, search for and remove any client-side JavaScript frame-busting code. These scripts typically check if top.location is different from self.location. This method is now considered obsolete and is easily bypassed by an attacker. Relying on it can create a false sense of security. Your defense strategy should be centered on modern, browser-enforced HTTP headers. If you find your headers are missing or need to be corrected, a CSP Policy Builder can help you generate the proper frame-ancestors directive with correct syntax.
Integrating Clickjacking Defense into Your Security Workflow
The use of HTTP headers like Content-Security-Policy and X-Frame-Options offers the most reliable method for preventing clickjacking. Applying these headers consistently across all sensitive pages of a web application is a major step towards securing user interactions.
Web security is not a static field. As applications are updated and new features are added, it is good practice to periodically re-verify these security settings. Using the checklist from the previous section as part of a regular development or deployment cycle helps maintain a secure configuration. A properly configured defense against clickjacking protects users from unwanted actions and helps preserve the integrity of the application.

