[ GF.dev ] All Tools →

Preventing Clickjacking with X-Frame-Options and CSP frame-ancestors

Published 2026-03-29 · Last modified 2026-03-29

Clickjacking is a deceptive attack where a malicious site overlays an invisible iframe of your application on top of seemingly innocent content, tricking users into clicking buttons or links they cannot see. The consequences range from unwanted social media likes to unauthorized fund transfers.

Two HTTP headers defend against clickjacking: the legacy X-Frame-Options and its modern successor, Content-Security-Policy: frame-ancestors. This article covers both and explains when to use each. For the full picture of security headers, see our complete security headers guide.

How Clickjacking Works

The attacker creates a page with an invisible <iframe> pointing to your application, positioned so that the user's click on the visible page actually hits a button inside the invisible iframe. Common attack scenarios include:

The attack works because the browser faithfully executes clicks on the framed page, including sending cookies and authentication tokens.

X-Frame-Options

The X-Frame-Options header is the original defense against clickjacking. It accepts three values:

X-Frame-Options: DENY

For most sites, DENY is the correct choice. Use SAMEORIGIN only if your application intentionally frames its own pages (for example, a preview feature in a CMS).

CSP frame-ancestors

The modern replacement is the frame-ancestors directive in Content Security Policy:

Content-Security-Policy: frame-ancestors 'none'

Advantages over X-Frame-Options:

For deep background on CSP, see Content Security Policy (CSP) Explained.

Should You Use Both?

Yes. Set both X-Frame-Options: DENY and Content-Security-Policy: frame-ancestors 'none'. Modern browsers use frame-ancestors and ignore X-Frame-Options when both are present. Older browsers that do not support CSP fall back to X-Frame-Options. This provides maximum coverage.

Nginx Configuration

add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "frame-ancestors 'none'" always;

If you have a full CSP, add frame-ancestors 'none' to your existing policy rather than setting a separate header.

Apache Configuration

Header always set X-Frame-Options "DENY"
Header always set Content-Security-Policy "frame-ancestors 'none'"

When You Need to Allow Framing

Some applications legitimately need to be framed — embeddable widgets, payment forms, or content displayed inside a partner's site. In these cases:

Testing Clickjacking Protection

Use our X-Frame-Options testing tool to verify your header is set correctly. You can also audit all your security headers in one scan. A quick manual test: create an HTML file with <iframe src="https://yoursite.com"> — if the frame loads, you are vulnerable.

Clickjacking prevention is one piece of a broader security posture. Combine it with HSTS, a strong CSP, and proper cookie security for comprehensive protection.

Try These Tools

Clickjacking Protection Test Security Headers Audit