Step-by-Step Guide
5 steps

How to Prevent Clickjacking

Clickjacking tricks users into clicking hidden elements by overlaying your site in an invisible iframe on a malicious page. The attacker can make users perform actions without their knowledge. This guide covers how to prevent your site from being framed.

Find security issues automatically before attackers do.

Follow These Steps

1

Add X-Frame-Options header

This header prevents your site from being loaded in iframes.

Code Example
// X-Frame-Options: DENY (recommended - blocks all framing)
// X-Frame-Options: SAMEORIGIN (allows framing by your own domain)

// In next.config.js
{ key: 'X-Frame-Options', value: 'DENY' }
2

Add CSP frame-ancestors directive

CSP frame-ancestors is the modern replacement for X-Frame-Options with more control.

Code Example
// Block all framing
Content-Security-Policy: frame-ancestors 'none'

// Allow framing by same origin
Content-Security-Policy: frame-ancestors 'self'

// Allow specific domains to frame your site
Content-Security-Policy: frame-ancestors 'self' https://trusted-partner.com
3

Use both headers for compatibility

Include both X-Frame-Options and CSP frame-ancestors for maximum browser support.

Code Example
// next.config.js
module.exports = {
  async headers() {
    return [{
      source: '/(.*)',
      headers: [
        { key: 'X-Frame-Options', value: 'DENY' },
        { key: 'Content-Security-Policy', value: "frame-ancestors 'none'" }
      ]
    }]
  }
}
4

Test your clickjacking protection

Verify that your site cannot be loaded in an iframe.

Code Example
<!-- Create a test HTML file -->
<html>
<body>
  <h1>Clickjacking Test</h1>
  <iframe src="https://yourdomain.com" width="500" height="500"></iframe>
  <!-- This iframe should show an error or be blank -->
</body>
</html>

Open this test file locally and verify the iframe does not load your site.

5

Handle exceptions for embedded content

If specific pages need to be embeddable, create targeted exceptions.

Code Example
// In next.config.js - different headers for different paths
module.exports = {
  async headers() {
    return [
      {
        source: '/embed/:path*',
        headers: [
          { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
          { key: 'Content-Security-Policy', value: "frame-ancestors 'self' https://trusted-site.com" }
        ]
      },
      {
        source: '/((?!embed).*)',
        headers: [
          { key: 'X-Frame-Options', value: 'DENY' },
          { key: 'Content-Security-Policy', value: "frame-ancestors 'none'" }
        ]
      }
    ]
  }
}

What You'll Achieve

Your application is protected against clickjacking with both X-Frame-Options and CSP frame-ancestors headers. Embeddable content has targeted exceptions while all other pages block framing.

Common Mistakes to Avoid

Mistake

Only using X-Frame-Options without CSP

Fix

X-Frame-Options is older and less flexible. Use both for compatibility and add CSP frame-ancestors for modern browsers.

Mistake

Setting SAMEORIGIN when DENY is needed

Fix

If your site never needs to be framed, use DENY. SAMEORIGIN is only needed if your own pages use iframes to embed other pages from your domain.

Frequently Asked Questions

Do I need both X-Frame-Options and CSP frame-ancestors?

For maximum compatibility, yes. Older browsers only support X-Frame-Options. Modern browsers prefer CSP frame-ancestors. Include both.

What if my site needs to be embedded in iframes?

Use CSP frame-ancestors to allow specific trusted domains. Use path-specific headers to only allow framing on pages designed for embedding.

Ready to Secure Your App?

VAS automatically scans your deployed app for the security issues covered in this guide. Get actionable results in minutes.

Start Security Scan