Clickjacking Protection: Two Headers, One Goal
Clickjacking attacks trick users into clicking invisible iframes overlay on seemingly legitimate content, causing unintended actions like transferring money, changing settings, or authorizing access. Two HTTP headers protect against this threat: the older X-Frame-Options and the newer CSP frame-ancestors directive.
Understanding which to use—or why to use both—is essential for comprehensive clickjacking protection in 2025.
X-Frame-Options: The Legacy Standard
X-Frame-Options was introduced by Microsoft in 2008 and became an industry standard for preventing pages from being embedded in frames.
Syntax and Values
DENY: Never allow framing
X-Frame-Options: DENY
SAMEORIGIN: Allow framing only by same origin
X-Frame-Options: SAMEORIGIN
ALLOW-FROM uri: Allow specific origin (deprecated, poor browser support)
X-Frame-Options: ALLOW-FROM https://trusted.com
Advantages
Wide browser support: Works in all browsers including Internet Explorer 8+ Simple implementation: Single header with straightforward values Proven track record: Over 15 years of deployment experience
Limitations
Single value only: Cannot specify multiple allowed origins ALLOW-FROM deprecated: Modern browsers removed support No granular control: Binary allow/deny per origin Being superseded: CSP frame-ancestors is the modern replacement
CSP frame-ancestors: The Modern Approach
frame-ancestors is part of Content Security Policy Level 2, offering more flexible frame control:
Syntax
Content-Security-Policy: frame-ancestors 'none'
Content-Security-Policy: frame-ancestors 'self'
Content-Security-Policy: frame-ancestors 'self' https://trusted.com https://another-trusted.com
Values
'none': Equivalent to X-Frame-Options: DENY 'self': Equivalent to X-Frame-Options: SAMEORIGIN Multiple origins: List any number of allowed domains Wildcard schemes: Use https: to allow all HTTPS origins
Advantages
Multiple origins: Allow framing by several specific domains Granular control: Precise whitelisting of trusted framers CSP integration: Part of broader security policy Modern standard: Recommended by security experts
Browser Support
Supported by all modern browsers since 2016, but legacy browser support lags behind X-Frame-Options.
Which Should You Use?
The 2025 recommendation: Use both for maximum compatibility and protection.
Dual Implementation
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
Modern browsers prioritize CSP frame-ancestors over X-Frame-Options. Older browsers fall back to X-Frame-Options. This approach ensures:
Maximum compatibility: Protection across all browsers Future-proofing: Ready for CSP-only future Defense in depth: Redundant protection if one fails
When CSP frame-ancestors Alone Suffices
If you don't need to support legacy browsers (IE11, very old mobile browsers), CSP frame-ancestors alone provides complete protection with greater flexibility.
Implementation Examples
Complete Denial
Block all framing:
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
Use for: Login pages, payment forms, administrative interfaces
Same-Origin Only
Allow framing only by your own site:
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
Use for: Applications where different pages frame each other
Multiple Trusted Origins
Allow specific external sites (CSP only):
Content-Security-Policy: frame-ancestors 'self' https://partner1.com https://partner2.com
X-Frame-Options cannot express this—use SAMEORIGIN as fallback:
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self' https://partner1.com https://partner2.com
Older browsers get less permissive policy (SAMEORIGIN) while modern browsers allow listed partners.
Common Mistakes
Conflicting Headers
Problem: Different policies in X-Frame-Options and frame-ancestors
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'none'
Result: Modern browsers use frame-ancestors ('none'), old browsers use X-Frame-Options (SAMEORIGIN), creating inconsistent protection
Solution: Make policies equivalent or intentionally more restrictive in X-Frame-Options
Using Deprecated ALLOW-FROM
Problem:
X-Frame-Options: ALLOW-FROM https://trusted.com
Result: Ignored by most modern browsers
Solution: Use CSP frame-ancestors for multiple origins, X-Frame-Options: SAMEORIGIN for legacy fallback
Missing from All Responses
Problem: Headers only on some responses, not all
Result: Unprotected pages can be framed
Solution: Set headers at web server level for all responses
Testing Frame Protection
Verify implementation:
Browser Developer Tools: Check Response Headers in Network tab
Manual Test: Attempt to embed page in iframe:
<iframe src="https://yoursite.com"></iframe>
Should result in console error: "Refused to display in a frame because it set 'X-Frame-Options' to 'deny'"
Security Scanners: Use Security Headers Analyzer
Exceptions: When to Allow Framing
Some legitimate use cases require framing:
Embedded widgets: Maps, videos, social media embeds Partner integrations: Trusted third parties embedding your content Internal applications: Dashboards framing various internal tools
For these scenarios:
- Use CSP frame-ancestors with specific allowed origins
- Never use 'unsafe-inline' or overly broad whitelists
- Regularly audit which origins are allowed
- Consider alternative integration methods (APIs, redirects)
Conclusion
Both X-Frame-Options and CSP frame-ancestors prevent clickjacking by controlling where your pages can be framed. X-Frame-Options offers broader legacy browser support but limited flexibility. CSP frame-ancestors provides granular control with multiple allowed origins but doesn't support very old browsers.
The 2025 best practice is implementing both headers with equivalent policies. Modern browsers use frame-ancestors for its flexibility, while older browsers fall back to X-Frame-Options. This dual approach ensures comprehensive protection across all browsers.
For maximum security on sensitive pages (login, payments, admin), use DENY/'none' to block all framing. For less sensitive content needing selective framing, use CSP frame-ancestors with explicitly whitelisted trusted origins and X-Frame-Options: SAMEORIGIN as fallback.
Validate your frame protection implementation with our Security Headers Analyzer to ensure proper configuration and comprehensive clickjacking defense.

