Skip to main content
SecScannerSecScanner
Security ChecksFree ToolsPricingBlog
Get Started
Sign InGet Started
← Back to Blog
HeadersFebruary 25, 20269 min read

Clickjacking Prevention: X-Frame-Options & CSP Guide

Learn what clickjacking is, how attackers use invisible iframes to trick users, and how to prevent it with X-Frame-Options and frame-ancestors CSP.

By SecScanner Team
Clickjacking Prevention: X-Frame-Options & CSP Guide

Clickjacking is a deceptive attack where a malicious site tricks users into clicking something different from what they perceive. By loading your website in a hidden iframe and overlaying it with enticing content, attackers can hijack clicks to perform unauthorized actions — transferring money, changing account settings, or granting permissions. This guide explains how clickjacking works and how to prevent it with X-Frame-Options and Content Security Policy frame-ancestors.

What Is Clickjacking?

Clickjacking (also known as a "UI redress attack") exploits the browser's ability to embed one page inside another using iframes. The attack works like this:

  1. The attacker creates a malicious webpage with an enticing button ("Click to win a prize!")
  2. Your legitimate website is loaded in an invisible iframe positioned over the button
  3. When the user clicks the visible button, they actually click on an element in your hidden page
  4. The action executes with the user's authenticated session — without their knowledge

Clickjacking Attack Example

<!-- Attacker's malicious page -->
<html>
<head>
  <style>
    .overlay {
      position: relative;
      width: 500px;
      height: 300px;
    }
    iframe {
      position: absolute;
      top: 0;
      left: 0;
      width: 500px;
      height: 300px;
      opacity: 0;          /* Invisible to the user */
      z-index: 2;          /* On top of everything */
    }
    .bait {
      position: absolute;
      top: 120px;           /* Aligned with the target button */
      left: 180px;
      z-index: 1;
      padding: 15px 30px;
      background: #22c55e;
      color: white;
      font-size: 24px;
      border-radius: 8px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <h1>Congratulations! You won!</h1>
  <div class="overlay">
    <div class="bait">Claim Your Prize</div>
    <!-- Your real page loaded invisibly -->
    <iframe src="https://yourbank.com/transfer?to=attacker&amount=1000"></iframe>
  </div>
</body>
</html>

The user sees "Claim Your Prize" but actually clicks the "Confirm Transfer" button on the bank's page.

Real-World Clickjacking Attacks

  • Facebook Likejacking — Attackers tricked users into "liking" pages they never intended to by overlaying invisible Facebook Like buttons on popular content
  • Twitter Worm (2009) — A "Don't Click" clickjacking attack that auto-tweeted from victims' accounts, spreading virally
  • Adobe Flash Settings — Clickjacking was used to enable webcam and microphone access through Flash's settings manager
  • Google Account Takeover — Researchers demonstrated clickjacking to change Google account recovery settings

How to Test for Clickjacking

Before implementing defenses, test whether your site is vulnerable:

<!-- Save as clickjack-test.html and open locally -->
<html>
<head><title>Clickjacking Test</title></head>
<body>
  <h1>Clickjacking Vulnerability Test</h1>
  <p>If you can see the page below in the frame, it's vulnerable:</p>
  <iframe src="https://your-site.com" width="800" height="600" style="border:2px solid red"></iframe>
</body>
</html>

If your site loads in the iframe, it's vulnerable. SecScanner automatically checks for clickjacking protection by verifying the presence of X-Frame-Options headers and CSP frame-ancestors directives.

Prevention: X-Frame-Options Header

X-Frame-Options is the original defense against clickjacking. It tells browsers whether your page can be framed:

Directives

# Prevent all framing (most secure for pages that should never be framed)
X-Frame-Options: DENY

# Allow framing only by same-origin pages
X-Frame-Options: SAMEORIGIN

# Allow framing by a specific origin (deprecated — use CSP instead)
X-Frame-Options: ALLOW-FROM https://trusted.com

Server Configuration

# Nginx
add_header X-Frame-Options "DENY" always;

# Apache
Header always set X-Frame-Options "DENY"

# Express.js
app.use((req, res, next) => {
  res.setHeader('X-Frame-Options', 'DENY');
  next();
});

# Next.js (next.config.js)
const nextConfig = {
  async headers() {
    return [{
      source: '/(.*)',
      headers: [
        { key: 'X-Frame-Options', value: 'DENY' },
      ],
    }];
  },
};

Prevention: CSP frame-ancestors (Modern Approach)

The frame-ancestors directive in Content Security Policy is the modern replacement for X-Frame-Options. It's more flexible and overrides X-Frame-Options when both are present:

# Prevent all framing
Content-Security-Policy: frame-ancestors 'none';

# Allow same-origin framing only
Content-Security-Policy: frame-ancestors 'self';

# Allow specific origins
Content-Security-Policy: frame-ancestors 'self' https://trusted-partner.com https://app.example.com;

# Allow framing by any HTTPS origin (rarely recommended)
Content-Security-Policy: frame-ancestors https:;

frame-ancestors vs X-Frame-Options

Feature X-Frame-Options CSP frame-ancestors
Multiple origins No Yes
Wildcard support No Yes (*.example.com)
Browser support All browsers All modern browsers
Takes precedence No (overridden by CSP) Yes
Standard status Deprecated Active W3C spec

Best practice: Set both headers for maximum compatibility. CSP frame-ancestors protects modern browsers while X-Frame-Options covers older ones.

Clickjacking Prevention for Common Scenarios

Standard Website (No Framing Needed)

X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none';

Site with Same-Origin Embeds

# When your own pages need to iframe other pages on the same domain
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self';

Widget or Embed Provider

# When partners need to embed your content
# Don't set X-Frame-Options (it can't handle multiple origins)
Content-Security-Policy: frame-ancestors 'self' https://partner1.com https://partner2.com;

Selective Protection (Per-Route)

// Express.js — different policies for different routes
app.use('/admin', (req, res, next) => {
  // Admin pages should never be framed
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
  next();
});

app.use('/embed', (req, res, next) => {
  // Embeddable widgets allow specific origins
  res.setHeader('Content-Security-Policy',
    "frame-ancestors 'self' https://partner.com");
  next();
});

Advanced Clickjacking Variants

Cursorjacking

The attacker changes the cursor's visual position, so clicks land on a different element than expected. Defense: same framing protections apply since the attack still requires iframing your page.

Drag-and-Drop Clickjacking

Instead of clicks, the attacker tricks users into dragging sensitive content (like authentication tokens) from your page into the attacker's page. The frame-ancestors directive prevents this by blocking the iframe entirely.

Double-Clickjacking

A timing-based variant where the first click opens a legitimate permission prompt, and the second click (intended for the bait) confirms it. Mitigation requires both framing protection and interaction timing defenses.

JavaScript-Based Defense (Framebusting)

As a fallback for environments where you can't control headers, JavaScript framebusting can provide some protection:

// Modern framebusting approach
if (window.self !== window.top) {
  // Page is being framed — break out
  window.top.location = window.self.location;
}

// More robust version
(function() {
  if (self === top) {
    // Not framed — show content
    document.documentElement.style.display = 'block';
  } else {
    // Framed — redirect to top
    top.location = self.location;
  }
})();

Warning: JavaScript framebusting is not reliable because attackers can use the sandbox attribute on iframes to disable scripts. Always use HTTP headers as the primary defense.

Clickjacking Prevention Checklist

  • Set X-Frame-Options: DENY on all pages that shouldn't be framed
  • Deploy Content-Security-Policy: frame-ancestors 'none' for modern browsers
  • Use SAMEORIGIN / 'self' only when your pages need to iframe each other
  • Apply stricter policies to sensitive pages (login, settings, payment)
  • Test framing protection with a simple iframe test page
  • Audit third-party integrations that may require framing exceptions
  • Add JavaScript framebusting as a defense-in-depth layer
  • Run SecScanner to verify clickjacking protection across your site

Clickjacking is easy to prevent but often overlooked. Two HTTP headers — X-Frame-Options and CSP frame-ancestors — block the attack entirely for most websites. Run a SecScanner scan to verify your site is protected, and make framing controls part of your standard security header deployment.

Related Articles

Headers

The Complete Guide to HTTP Security Headers

10 min read

General

XSS Attack Prevention: Cross-Site Scripting Explained

12 min read

Check Your Website Security

Want to see how your website measures up? Run a free security scan with SecScanner to identify vulnerabilities and get actionable remediation guidance.

Scan Your Website Free
Security Headers CheckerHeader Security Checks

On This Page

Product

  • Security Checks
  • Free Tools
  • SSL Checker
  • Vulnerability Scanner
  • Email Security
  • Pricing
  • Compliance
  • Security Reports

Popular Checks

  • CSP Check
  • HSTS Check
  • TLS Version Check
  • SSL Expiry Check
  • SPF/DKIM/DMARC Check
  • Cookie Security Check
  • JS Vulnerability Scan
  • OCSP Stapling Check

Resources

  • Blog
  • Glossary
  • Contact

Legal

  • Terms of Use
  • Privacy Policy
  • Refund Policy
  • Cookie Policy

© 2025-2026 SecScanner. All rights reserved.