X-Frame-Options Explained: Prevent Clickjacking

X-Frame-Options stops attackers from embedding your site in an invisible iframe and tricking users into clicking hidden buttons or links. Here is everything you need to know about this header.


The X-Frame-Options header tells the browser whether your page is allowed to be displayed inside a <frame>, <iframe>,<embed>, or <object> element. Its primary purpose is to prevent clickjacking — an attack that overlays a transparent iframe of your site on top of a malicious page to steal clicks.

What Is a Clickjacking Attack?

In a clickjacking attack, an attacker creates a web page with a transparent or invisible iframe positioned precisely over a button or link they want the victim to click. The victim sees the attacker's page and thinks they are interacting with it, but their clicks are actually registered by the hidden page inside the iframe — which could be their bank, email provider, or social media account.

Common clickjacking targets include:

  • Account settings pages with "Delete account" or "Change password" actions.
  • Payment confirmation pages.
  • Social sharing and like buttons.
  • OAuth authorisation consent screens.

Because the victim is already authenticated in the target site, the hidden iframe loads the real authenticated page. No credentials need to be stolen — just clicks.

http
X-Frame-Options: DENY

X-Frame-Options Values

DENY

The page cannot be displayed in a frame on any domain, including the same origin. This is the most restrictive and most secure option. Use it for any page that does not need to be embedded in an iframe anywhere.

SAMEORIGIN

The page can only be framed by pages on the same origin (same scheme, host, and port). This is the right choice when you have a legitimate need to embed your own pages — for example, a dashboard that renders sub-pages in an iframe.

ALLOW-FROM uri (deprecated)

The original specification included a third value, ALLOW-FROM https://trusted.example.com, to permit framing by a specific origin. This value was never consistently implemented across browsers and is now formally deprecated. Modern browser versions ignore it entirely. Use the CSP frame-ancestors directive instead.

ValueMeaningWhen to use
DENYNo framing allowed by anyoneDefault for most pages
SAMEORIGINFraming allowed by same-origin pages onlyInternal iframe embedding
ALLOW-FROM uriFraming by specific URL (deprecated)Do not use — use CSP instead
ALLOW-FROM Is No Longer SupportedChrome, Firefox, and Safari have all dropped support for ALLOW-FROM. If you need to allow a specific third-party origin to embed your page, use Content-Security-Policy: frame-ancestors https://trusted.example.com instead.

The Modern Replacement: CSP frame-ancestors

The frame-ancestors directive in Content Security Policy supersedesX-Frame-Options for all browsers that support CSP Level 2 (which is all modern browsers). It offers several advantages:

  • Multiple origins can be allowlisted in a single directive.
  • Wildcard and scheme-based matching is supported.
  • It is part of the standard CSP header you are already using for other protections.
http
Content-Security-Policy: frame-ancestors 'none'

frame-ancestors 'none' is equivalent to X-Frame-Options: DENY.frame-ancestors 'self' is equivalent to SAMEORIGIN.

When Should You Still Use X-Frame-Options?

Despite being superseded, X-Frame-Options still has a role:

  • Legacy browser support. Internet Explorer 11 does not support CSPframe-ancestors. If your audience includes IE11 users, keepX-Frame-Options as a fallback.
  • Defence in depth. Sending both headers adds redundancy. If a browser has a CSP parsing bug, X-Frame-Options provides a safety net.
  • You have no CSP yet. Adding X-Frame-Options: DENY is a one-line win that closes clickjacking risk immediately while you build out a full CSP.
Send Both HeadersThe safest approach for most sites is to send both X-Frame-Options: DENY andContent-Security-Policy: frame-ancestors 'none'. Modern browsers will use the CSP directive; older browsers will fall back to X-Frame-Options.

How to Set X-Frame-Options in Nginx and Apache

Nginx

nginx
add_header X-Frame-Options "DENY" always;

Apache

apache
Header always set X-Frame-Options "DENY"

How to Check the Header

Use the ShowDNS HTTP Header Checker to inspect the X-Frame-Options value your server is returning. You can also open browser DevTools (F12), go to the Network tab, select the main document request, and check the Response Headers section. The Security Headers Scanner will flag the header as missing if it is absent.

Frequently Asked Questions

Does X-Frame-Options work on all browsers?

DENY and SAMEORIGIN are supported in all major browsers including Chrome, Firefox, Safari, Edge, and Internet Explorer 11. The ALLOW-FROM value is not reliably supported in any modern browser.

Does X-Frame-Options protect against all clickjacking?

It prevents the most common iframe-based clickjacking. However, some creative variants such as drag-and-drop data theft or cursor jacking may not be fully addressed by this header alone. A comprehensive CSP and regular security testing provide broader protection.

My site uses iframes legitimately. What should I do?

If you need to embed your own pages in iframes within your own site, useX-Frame-Options: SAMEORIGIN or frame-ancestors 'self'. If a specific trusted third-party site needs to embed your pages, list that origin inframe-ancestors within your CSP.

Does the header need to be set on every page?

Yes. X-Frame-Options is a per-response header. Set it globally in your server configuration so it applies to all responses automatically. If you only set it on some pages, the unprotected pages remain vulnerable.

Related Articles