This is my web page.
If this window is not blank, the iframe source URL can be framed!
If the target page renders inside the iframe, it is frameable. If it shows blank, framing is prevented server-side.
**Attack setup:**
Say ''example.com'' has a money transfer page at ''https://www.example.com/transfer_money'' that accepts ''recipient'' and ''amount'' URL parameters to pre-fill the form. The attacker embeds this page in an iframe on their site, overlays decoy content on top, and sets the iframe to nearly invisible:
Welcome to my site!
Subscribe to our cybersecurity newsletter!
Key CSS properties:
* ''opacity:0.00001'' -- makes the iframe nearly invisible while keeping it clickable
* ''z-index:1'' on the iframe (higher z-index = on top in click detection)
* ''z-index:-1'' on the decoy (rendered below the iframe)
* ''position:absolute'' on the decoy to overlay it precisely
The attacker positions the iframe so the Transfer Balance button sits directly over the Subscribe button. The victim sees only the newsletter form; clicking Submit actually executes the bank transfer.
===== Prevention =====
Two conditions must exist for clickjacking to succeed:
- The vulnerable page contains a state-changing action (changes account data, transfers funds, etc.)
- The page allows itself to be framed by other origins
**X-Frame-Options header** -- instructs browsers whether the page can be framed:
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
* ''DENY'' -- cannot be framed at all
* ''SAMEORIGIN'' -- only pages from the same origin can frame it
**Content-Security-Policy header** -- ''frame-ancestors'' directive:
Content-Security-Policy: frame-ancestors 'none';
Content-Security-Policy: frame-ancestors 'self';
Content-Security-Policy: frame-ancestors 'self' *.example.com;
**SameSite cookies** -- if session cookies are ''SameSite=Strict'' or ''SameSite=Lax'', they will not be sent in requests made within a third-party iframe. This means even if the page is framed, the victim will not be authenticated, defeating the attack for any action that requires authentication:
Set-Cookie: PHPSESSID=UEhQUOVTUOlE; Max-Age=86400; Secure; HttpOnly; SameSite=Strict
===== Hunting for Clickjacking =====
==== Step 1: Find State-Changing Actions ====
Clickjacking is only valuable when the target page contains a state-changing action achievable via clicks alone (not keyboard input). Go through the application and list every action that changes account state, along with the URL:
* Change password: ''bank.example.com/password_change''
* Transfer balance: ''bank.example.com/transfer_money''
* Unlink external account: ''bank.example.com/unlink''
Actions that require explicit keyboard input (typing a recipient account number) are generally not feasible because they require too much social engineering.
==== Step 2: Check Response Headers ====
Intercept the response for each state-changing page in Burp. Look for:
* ''X-Frame-Options'' header (DENY or SAMEORIGIN)
* ''Content-Security-Policy: frame-ancestors'' directive
* ''SameSite'' flag on the session cookie
If none of these are present, the page may be vulnerable. Even if the site uses JavaScript frame-busting instead, that is often bypassable.
==== Step 3: Confirm Frameability ====
Create a test HTML page that frames the target:
Clickjack test page
Web page is vulnerable to clickjacking if the iframe is populated with the target page!
Open this page in a browser. If the target page renders inside the iframe, framing is possible.
==== Step 4: Confirm the Vulnerability ====
Execute the state-changing action against your own test account through the framed page. If the action succeeds when triggered via click through the iframe, the vulnerability is confirmed.
===== Bypassing Protections =====
If the site uses JavaScript frame-busting code instead of HTTP response headers, it may be bypassable. A common pattern:
if (top.location == self.location){
// Allow framing.
}
else{
// Disallow framing.
}
This compares the top frame's location to the current frame's location. If the top frame is a page on the victim's own domain (e.g., one that allows embedding custom iframes -- profile links, social share widgets), you can exploit this with the **double iframe trick**:
- Host a page on ''attacker.com'' that frames the victim's sensitive functionality
- Embed your ''attacker.com'' page inside a page hosted on ''victim.com'' that allows custom iframes
- Now ''top.location'' and ''self.location'' both point to ''victim.com''; the frame-busting code approves it
===== Escalating the Attack =====
Focus on the most sensitive actions for maximum impact:
* A balance transfer page is critical severity; a theme-color-change page is low
* Chain multiple clickjacking vulnerabilities -- for example, change the billing email to your own, then trigger "send account summary to billing email" to receive the victim's PII (address, phone number, credit card info)
For the chained attack HTML:
Welcome to my site!