Skip to main content

Clickjacking

Medium

UI Redress Attack

Clickjacking overlays an invisible iframe of your site over a malicious page. Users think they're clicking the malicious page's UI but are actually clicking your site. X-Frame-Options and Content-Security-Policy frame-ancestors prevent your pages from being embedded in iframes.

Overview

A clickjacking attack places your website in a transparent iframe overlaid on the attacker's page. The attacker positions an interactive element (a button, form, link) directly under the victim's cursor. When the victim clicks on what appears to be the attacker's content, they're actually clicking on the hidden iframe.

This can result in unintended actions: liking a post, making a purchase, changing account settings, or enabling a camera. The attack is invisible to the user – the iframe is styled with opacity: 0 and z-index manipulation.

X-Frame-Options: DENY is the legacy defense. The modern replacement is Content-Security-Policy with the frame-ancestors directive, which is more flexible and overrides X-Frame-Options in modern browsers.

The Attack: Transparent Iframe Overlay

The attacker overlays a transparent iframe of the target site over their own page. Victim clicks appear to interact with the attacker's page but actually trigger actions on the framed site.

Clickjacking attack page structure
http
<!-- Attacker's page -->
<style>
  iframe {
    position: absolute; opacity: 0.001;
    width: 100%; height: 100%;
    z-index: 9999;
  }
  #decoy { position: absolute; top: 340px; left: 180px; }
</style>
<div id="decoy">Click here to win!</div>
<iframe src="https://bank.com/confirm-transfer"></iframe>

Defenses

1Content-Security-Policy: frame-ancestors

The modern defense. frame-ancestors specifies which origins are allowed to embed this page in a frame. Use frame-ancestors 'none' to block all framing, or frame-ancestors 'self' to allow only same-origin framing.

Block all framing
http
Content-Security-Policy: frame-ancestors 'none'

2X-Frame-Options

The legacy header, still widely supported. DENY blocks all framing. SAMEORIGIN allows same-origin framing. ALLOW-FROM is deprecated (not supported in Chrome/Firefox). Use CSP frame-ancestors as the primary defense with X-Frame-Options as a fallback.

X-Frame-Options deny
http
X-Frame-Options: DENY

Checklist

  • Set Content-Security-Policy: frame-ancestors 'none' on all pages that don't need to be framed
  • Add X-Frame-Options: DENY as a fallback for older browsers
  • If your site uses legitimate framing (widgets, embeds), use frame-ancestors 'self' or specific origins
  • Test with OWASP's clickjacking test tool after deploying
  • Apply clickjacking protection to authentication pages, transaction confirmations, and settings pages at minimum

Related Headers

FAQ

X-Frame-Options vs CSP frame-ancestors – which should I use?

Use both. CSP frame-ancestors is the modern standard and overrides X-Frame-Options in browsers that support it. X-Frame-Options is the fallback for older browsers. Set both: X-Frame-Options: DENY and Content-Security-Policy: frame-ancestors 'none'.

Does clickjacking work against HTTPS sites?

Yes. HTTPS does not prevent clickjacking – it only encrypts the connection. The attack works regardless of whether the framed site uses HTTP or HTTPS.