SecHead
Escanear un sitioContáctenos
Header Guide17 min read

X-Frame-Options vs frame-ancestors: What's the Difference?

Both X-Frame-Options and the CSP frame-ancestors directive protect against clickjacking. Learn which one to use, how they differ, and when to use both.

SL
Seven Labs · 10 February 2026
3,342 words

X-Frame-Options vs frame-ancestors: The Definitive Guide to Clickjacking Prevention

Quick Answer

X-Frame-Options and CSP's frame-ancestors directive are both HTTP response headers used for clickjacking prevention. While they serve the same fundamental purpose-preventing untrusted websites from embedding your content inside iframes-they operate differently.

  • frame-ancestors is the modern, more flexible standard (part of Content Security Policy Level 2) that allows specifying multiple trusted origins, wildcards, and complex rules.
  • X-Frame-Options is an older, legacy header with limited capabilities (allowing only one origin via the deprecated ALLOW-FROM directive), and is best used as a fallback for legacy browsers.

Best Practice for 2026: Implement frame-ancestors as your primary defense and add X-Frame-Options as a legacy fallback. Modern browsers will prioritize the CSP directive and ignore X-Frame-Options entirely, giving you the best of both worlds.

Scan your site with SecHead → to check which clickjacking prevention you have in place.


People Also Ask

  • What is the difference between X-Frame-Options and frame-ancestors? frame-ancestors is part of CSP, allows multiple domains, wildcards, and is the modern standard. X-Frame-Options is a legacy header that is limited to a single origin or a blanket denial.
  • Do I need both X-Frame-Options and frame-ancestors? Using both provides maximum compatibility. Older browsers (like IE) respect X-Frame-Options, while modern browsers use frame-ancestors.
  • Is X-Frame-Options deprecated? The header itself is not fully deprecated, but its ALLOW-FROM directive is. frame-ancestors is the recommended path forward.

What is Clickjacking (UI Redressing)?

Before diving into the technical nuances of X-Frame-Options and frame-ancestors, it is critical for System Administrators and Web Developers to thoroughly understand the threat these headers mitigate. Clickjacking, also known as UI Redressing or UI redressing attack, is a sophisticated, malicious technique where an attacker tricks a user into clicking on a completely different web element from what the user perceives.

Unlike Cross-Site Scripting (XSS) where malicious code is injected, clickjacking weaponizes the legitimate interface of the target application.

The Anatomy of a Clickjacking Attack

In a typical clickjacking attack, the adversary creates an attractive, deceptive website designed to lure in victims. On this site, they embed the target website (for instance, a cryptocurrency exchange, an email client, or a social media account) inside an <iframe>. The attacker then uses CSS (Cascading Style Sheets) to manipulate the visual presentation, setting the target iframe to be completely transparent using opacity: 0 or positioning it off-screen but overlapping the active viewport window.

Over this invisible iframe, the attacker layers attractive, visible elements-such as a button that says "Claim Your Prize", "Play Video", or "Download File".

When the user clicks the visible decoy button, their browser fundamentally registers a click on the invisible iframe stacked directly beneath it. If the user is authenticated into the target site (using active session cookies), the attacker can successfully hijack that session to perform unauthorized actions like transferring funds, changing account permissions, approving OAuth grants, or deleting critical data.

https://evil-attacker.com/win-prize

[ WIN A FREE IPHONE ] <--- Visible attacker button (z-index: 1)
[ TRANSFER $1000  ] <--- Invisible bank iframe underneath (z-index: 2, opacity: 0)

User clicks "WIN A FREE IPHONE"
Result: Transfer $1000 initiated via victim's active session!

Because the click originates from the user's authentic session, and the request comes straight from their browser, standard protections like CSRF (Cross-Site Request Forgery) tokens often fail to stop clickjacking. The browser genuinely believes the user intended to perform the action. The server processes the request as entirely legitimate.

This is exactly where clickjacking prevention headers step in. By instructing the browser explicitly where a web page is permitted to be framed, Security Engineers and site administrators can completely neutralize this attack vector at the browser level.


The Legacy Standard: X-Frame-Options

Introduced originally by Microsoft in Internet Explorer 8 (around 2009) as a proprietary X- extension header, X-Frame-Options (XFO) was the internet's first unified defense against UI redressing. Recognizing its immense security value, it quickly became a massive industry standard adopted natively by Chrome, Firefox, Safari, and Opera.

The header explicitly tells the browser whether it should allow a page to be rendered inside a <frame>, <iframe>, <embed>, or <object>.

X-Frame-Options Directives in Detail

The X-Frame-Options header supports three distinct directives, though only two are viable today:

  1. DENY This is the most secure and most restrictive setting. It instructs the browser to definitively block all framing of the page, regardless of the site attempting to frame it. Even if your own website tries to embed another page from your domain into an iframe, the browser will forcefully block it. Use this for highly sensitive pages like password resets or financial transfers.

    HTTP/1.1 200 OK
    Content-Type: text/html
    X-Frame-Options: DENY
    
  2. SAMEORIGIN This directive allows the page to be displayed in a frame, but only if the site attempting to frame it shares the exact same origin (scheme, hostname, and port) as the page itself. This is the most commonly used directive because it balances robust security with practical functionality, allowing a site's internal applications, dashboards, and single-page apps to frame its own pages without exposing it to the open internet.

  3. ALLOW-FROM uri (Obsolete/Deprecated) The ALLOW-FROM directive was designed to allow framing from a specific, specified external origin (e.g., ALLOW-FROM https://trusted-partner.com).

    The Problem with ALLOW-FROM: The architectural execution of ALLOW-FROM was deeply flawed from the start. Firstly, it only permitted a single origin string. If you needed to allow framing from three different partner domains, it was technically impossible to specify a list. Security Engineers were forced into complex backend logic to dynamically rewrite the header based on the incoming Referer, which was fragile and spoofable.

    Secondly, browser implementation was horribly fragmented. Google Chrome and Apple Safari never formally supported it, choosing instead to ignore the directive entirely. This resulted in either completely broken functionality for end-users or total bypass of security. Due to these massive limitations, ALLOW-FROM is considered obsolete and unsupported today.


The Modern Standard: CSP frame-ancestors

Content Security Policy (CSP) completely revolutionized web security by giving Web Developers hyper-granular control over the resources an application is permitted to load and execute. As part of CSP Level 2 (formalized by the W3C in 2014), the frame-ancestors directive was introduced, specifically engineered as a vastly superior, highly scalable replacement for X-Frame-Options.

The frame-ancestors directive specifies the valid parent origins that may embed a page using <frame>, <iframe>, <object>, <embed>, or <applet>.

The Power and Flexibility of frame-ancestors

Unlike its legacy predecessor, frame-ancestors is incredibly flexible and built for the modern, interconnected web. It fully supports the following configurations:

  1. 'none' (Equivalent to XFO: DENY) Prevents any domain from framing the content. Note the mandatory single quotes around the keyword.

  2. 'self' (Equivalent to XFO: SAMEORIGIN) Allows framing only by pages from the same origin. Again, single quotes are required.

  3. Specific Origins and Multiple Domains This is where frame-ancestors proves its worth for Web Developers. You can specify a space-separated list of multiple trusted origins. You can also securely use wildcards for subdomains or specify specific schemes.

    HTTP/1.1 200 OK
    Content-Type: text/html
    Content-Security-Policy: default-src 'self'; frame-ancestors 'self' https://trusted-partner.com https://*.example.com
    

In the comprehensive example above, the web page can be legally framed by its own origin, exactly https://trusted-partner.com, and any verified subdomain of example.com served explicitly over HTTPS.

Protocol and Scheme Whitelisting

Beyond domain names, System Administrators can also whitelist specific protocols. For example, custom application schemes (like android-app:// or ios-app:// or vscode://) can be authorized, allowing seamless integration with native mobile wrappers and desktop applications without globally compromising web security.


X-Frame-Options vs frame-ancestors: The Core Differences

When evaluating X-Frame-Options vs frame-ancestors for robust clickjacking prevention, Security Engineers must understand their core architectural differences and how browser rendering engines handle them:

FeatureX-Frame-OptionsCSP frame-ancestors
Release Era2009 (Legacy standard)2014 (CSP Level 2 standard)
Allows Multiple Origins?NoYes (Space separated lists)
Wildcard Support?NoYes (e.g., *.domain.com)
Reporting Mode Support?NoYes (via Report-Only)
Native Browser SupportUniversal (including ancient IE8+)All Modern Browsers (Chrome, Firefox, Safari, Edge)
Precedence LevelLowerHigher (Overrides XFO)

The Critical Precedence Rule

The single most crucial behavioral detail for Web Developers to master is the precedence rule. If an HTTP response contains both an X-Frame-Options header and a CSP containing a frame-ancestors directive, all modern, spec-compliant browsers will dynamically process frame-ancestors and completely ignore X-Frame-Options.

This deliberate architectural design choice by browser vendors (like Google and Mozilla) allows developers to safely implement both headers simultaneously. This ensures maximum backwards compatibility for legacy enterprise clients without causing rendering conflicts for modern users.


Implementing Clickjacking Prevention Across Stacks

Security Engineers must ensure these headers are implemented consistently, ideally at the network edge (reverse proxy/CDN) or deeply within the core application framework itself. Below are exhaustive configuration snippets for the most common deployment stacks in the industry.

Nginx Configuration

To implement robust, production-ready clickjacking prevention in Nginx, add the following directives to your server or location block.

# Nginx comprehensive clickjacking defense
# XFO acts as the critical fallback for legacy clients
add_header X-Frame-Options "SAMEORIGIN" always;

# Modern CSP frame-ancestors handles all modern traffic
add_header Content-Security-Policy "frame-ancestors 'self' https://trusted.app.com;" always;

Apache Configuration

For Apache HTTP Server environments, strictly ensure the mod_headers module is permanently enabled (a2enmod headers). Add these precise directives to your .htaccess file or primary virtual host configuration:

<IfModule mod_headers.c>
    # Legacy protection layer
    Header always set X-Frame-Options "SAMEORIGIN"
    
    # Modern CSP layer
    Header always set Content-Security-Policy "frame-ancestors 'self' https://trusted.app.com"
</IfModule>

Node.js (Express) Configuration using Helmet

In the vast Node.js ecosystem, the helmet middleware is the undisputed industry standard for intelligently managing security headers.

const express = require('express');
const helmet = require('helmet');
const app = express();

// Helmet automatically sets X-Frame-Options to SAMEORIGIN by default upon initialization
app.use(helmet());

// To expertly configure CSP frame-ancestors specifically:
app.use(
  helmet.contentSecurityPolicy({
    useDefaults: true,
    directives: {
      "frame-ancestors": ["'self'", "https://trusted.app.com", "https://*.partner-network.com"],
    },
  })
);

Next.js Configuration

In modern React meta-frameworks like Next.js, HTTP security headers are cleanly defined in the root configuration file to be applied edge-side during SSR or static delivery.

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        // Apply headers globally to all routes
        source: '/(.*)',
        headers: [
          {
            key: 'X-Frame-Options',
            value: 'SAMEORIGIN'
          },
          {
            key: 'Content-Security-Policy',
            value: "frame-ancestors 'self' https://trusted.app.com"
          }
        ],
      },
    ]
  },
}

Java Spring Boot Configuration

In enterprise Java environments using Spring Security, clickjacking protection is enabled by default (usually as DENY). To customize it to use both:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .headers()
                .frameOptions().sameOrigin() // Sets X-Frame-Options
                .contentSecurityPolicy("frame-ancestors 'self' https://trusted.app.com"); // Sets CSP
    }
}

Real-World Troubleshooting and Edge Cases

Implementing strict security headers is rarely without friction. System administrators frequently encounter broken application integrations when critical third-party services (like payment gateways, support widgets, or analytics dashboards) rely heavily on iframes.

Resolving the Chrome Console Refused Alert

When a legitimate iframe is forcefully blocked by frame-ancestors, the end-user simply sees a broken window (or the browser's generic sad-face error), while the developer sees a specific, highly detailed error in the browser console.

[Error] Refused to frame 'https://yourdomain.com/' because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'self'".

Actionable Troubleshooting Steps:

  1. Identify the Blocked Ancestor: Look closely at the origin attempting the framing. Is it a legitimate, contracted partner?
  2. Update the CSP Payload: If the framing is legitimate, append the origin URL directly to your frame-ancestors directive string. Crucial Note: Do not attempt to append the origin to X-Frame-Options as the ALLOW-FROM syntax is fully deprecated.
  3. Check for Header Conflicts: Ensure you aren't inadvertently sending multiple, conflicting CSP headers. If multiple CSP headers are transmitted, the browser rigidly enforces the most restrictive intersection of them all, which can cause unexpected breakage.

Utilizing CSP Report-Only for Safe Deployments

A massive, enterprise-grade advantage of frame-ancestors over X-Frame-Options is the built-in ability to use Content-Security-Policy-Report-Only.

If you are a Security Engineer tasked with deploying clickjacking prevention on a massive, highly trafficked legacy application, you might not know exactly who is framing your app across the internet. Enforcing a strict DENY immediately could catastrophically break critical business workflows and generate massive customer support tickets.

HTTP/1.1 200 OK
Content-Security-Policy-Report-Only: frame-ancestors 'none'; report-uri https://sechead.example.com/csp-report-endpoint

By deploying the report-only header, the browser will gracefully allow the framing to occur for the end-user, but will simultaneously ping your telemetry endpoint with a rich JSON payload detailing the exact violation. This allows you to safely map out legitimate framing use cases over several weeks, update your policies, and eventually flip the switch to hard enforcement without risking downtime.


SecHead's Security Header Scoring Mechanism

At SecHead, our sophisticated automated vulnerability scanners meticulously analyze your raw HTTP responses to ensure optimal clickjacking prevention is actively deployed.

  • Pass / A+ Rating: We successfully verify the presence of a robust, well-formed frame-ancestors directive OR a highly restrictive X-Frame-Options header (strictly DENY or SAMEORIGIN).
  • Warning / Penalty Score: If neither header is detected in the response, your web application is highly vulnerable to UI redressing, and your security posture score will drop significantly.
  • Conflict Handling: If both headers are present but offer wildly conflicting instructions (e.g., XFO: DENY but CSP: frame-ancestors 'self'), SecHead will raise a low-severity informational note. We do not heavily penalize this specific scenario because modern rendering engines gracefully handle the conflict by strictly honoring the CSP, but it is considered poor administrative hygiene and can confuse downstream developers.

Comprehensive FAQ on Clickjacking Prevention

1. What happens if my server accidentally sends multiple X-Frame-Options headers? If a server misconfigures and sends multiple X-Frame-Options headers, the resulting behavior is undefined and varies drastically by browser. Some rendering engines will enforce the strictest header found, while others might critically fault and ignore the headers entirely, leaving you completely vulnerable. Always strictly ensure your reverse proxy or application sets exactly one cohesive header.

2. How does frame-ancestors interact with the CSP default-src directive? The frame-ancestors directive is highly unique; it does not natively fall back to default-src. If you do not explicitly define frame-ancestors, absolutely any site can frame your application, regardless of how restrictive your default-src policy is.

3. Is there a way to allow framing only for specific directory paths? No. HTTP response headers, including CSP and XFO, apply globally to the entire HTTP response (the specific document being served). You can dynamically configure your web server (like Nginx or Express) to serve different headers for different paths, but the security directive itself applies per-page, not application-wide.

4. Does clickjacking affect native mobile applications? Clickjacking is primarily a browser-based attack involving malicious iframes. However, mobile WebViews (in iOS and Android) can be highly vulnerable if they load untrusted third-party web content alongside sensitive, authenticated web content. Properly securing WebViews is a critical mobile security engineering task.

5. How do I dynamically allow framing from any subdomain? Use frame-ancestors seamlessly with a wildcard character: Content-Security-Policy: frame-ancestors https://*.yourdomain.com.

6. Why is my frame-ancestors header being silently ignored by the browser? The most frequent reasons are basic syntax errors (e.g., missing the vital single quotes around 'self' or 'none'), or the unintentional presence of a conflicting, vastly stricter CSP header on the exact same HTTP response.

7. Can an attacker simply bypass X-Frame-Options by using a reverse proxy? No. X-Frame-Options is strictly enforced client-side by the end-user's web browser. Even if an attacker completely proxies the content, the victim's browser will still meticulously read the header and refuse to render the frame. If the attacker malicious strips the header at the proxy layer, the victim's browser won't see it-but the attacker fundamentally cannot force the victim to visit the proxied version while magically retaining the victim's authenticated session cookies.

8. What is the modern equivalent of X-Frame-Options ALLOW-FROM in CSP? In CSP, you elegantly bypass the need for ALLOW-FROM by simply listing the trusted origins space-separated: frame-ancestors https://trusted-site1.com https://trusted-site2.com.

9. Does the SAMEORIGIN directive allow subdomains to frame the parent page? No, it does not. The SAMEORIGIN directive (and similarly, frame-ancestors 'self') strictly demands that the scheme (http/https), hostname, and exact port all match perfectly. For instance, app.example.com cannot securely frame www.example.com under SAMEORIGIN.

10. How do I rapidly test if my clickjacking prevention is actively working? You can rapidly write a simple local HTML file containing an iframe pointing to your production site and open it in any browser.

<iframe src="https://your-secure-production-site.com" width="800" height="600"></iframe>

If your site loads and renders the UI, you are highly vulnerable. If the iframe appears entirely blank and the browser developer console displays a red blocking error, your prevention is active and functional.

11. Does CSP frame-src do the exact same thing as frame-ancestors? No. This is a massively common point of confusion among Web Developers. frame-src strictly controls what iframes your specific page is safely allowed to load (outgoing connections). frame-ancestors strictly controls who on the internet is safely allowed to load your page inside an iframe (incoming connections).

12. Will these headers completely protect against Cross-Site Scripting (XSS)? No, absolutely not. frame-ancestors and X-Frame-Options are engineered to strictly prevent clickjacking and UI redressing. Other distinct CSP directives, specifically script-src and object-src, are mandatory to successfully mitigate XSS vulnerabilities.

13. Are there any measurable performance impacts to adding these headers? No. HTTP response headers generally add only a few bytes to the total payload size and are processed instantaneously by the browser's core rendering engine. There is zero perceptible performance impact to the end-user.

14. What if I use a modern CDN like Cloudflare or Fastly? CDNs usually seamlessly respect origin headers, but you can also programmatically configure your CDN (e.g., using advanced Cloudflare Workers, Edge Functions, or simple Page Rules) to forcefully and consistently inject these security headers directly at the edge, guaranteeing absolute protection even if the backend origin server intermittently fails to set them.

15. Can I use a simple HTML meta tag for frame-ancestors? No. Unlike some other specific CSP directives, frame-ancestors simply cannot be reliably delivered via an inline HTML <meta http-equiv="Content-Security-Policy"> tag. It must strictly be delivered as a proper HTTP response header.


Conclusion

Securing your modern web applications aggressively against clickjacking is an absolutely mandatory requirement for any organization actively handling sensitive customer data, managing authenticated user sessions, or processing financial transactions.

The historical evolution from the rudimentary X-Frame-Options to the robust Content Security Policy frame-ancestors directive beautifully reflects the web's rapidly growing need for nuanced, highly flexible security controls. While X-Frame-Options proudly paved the way and still reliably serves as a highly viable fallback mechanism, frame-ancestors natively provides the surgical precision explicitly required by modern, heavily componentized web architectures.

By strictly prioritizing frame-ancestors deep within your Content Security Policy and systematically auditing your production configurations with specialized tools like SecHead, elite Web Developers, Security Engineers, and System Administrators can confidently and permanently close the door on sophisticated UI redressing attacks.


For an incredibly comprehensive guide to thoroughly fortifying your web applications against modern threats, carefully review our massive complete security headers checklist and deeply dive into the complex mechanics of Content Security Policy in our exhaustive CSP explained guide.

# SEO Metadata
Meta Title: "X-Frame-Options vs frame-ancestors: Clickjacking Prevention Guide"
Meta Description: "A comprehensive guide for Web Developers and Security Engineers on preventing clickjacking. Learn the critical differences between X-Frame-Options and CSP frame-ancestors."
URL Slug: /blog/x-frame-options-vs-frame-ancestors
Keywords: Clickjacking Prevention, X-Frame-Options, frame-ancestors, CSP, UI Redressing, Security Headers, SecHead

Continue your journey into web security with these related, deep-dive articles from the SecHead team:

Related articles

Free tool

Check your own security headers

Instant grade, plain-language explanations, and a full remediation plan - no signup needed.

Scan your site now →