How to Configure X-Frame-Options Headers for Clickjacking Prevention

To prevent clickjacking attacks, configure the X-Frame-Options HTTP header to DENY or SAMEORIGIN on every HTTP response, implementing it at the reverse proxy, application server, or edge CDN level according to the Front-End-Checklist security guidelines.

The Front-End-Checklist repository by thedaviddias identifies X-Frame-Options (XFO) as a medium-priority security requirement that protects users from clickjacking, a technique where attackers embed your site in invisible <iframe> elements to hijack user interactions. Found in the repository's README.md at lines 602–605, this recommendation cites Scott Helme's security guide and RFC 7034 as authoritative sources, emphasizing the need for global header deployment unless specific embedding use cases exist.

Understanding X-Frame-Options Directives

When a browser receives an X-Frame-Options header in the HTTP response, it validates the directive before rendering the page inside a frame. If the policy is violated, the browser blocks rendering entirely, mitigating the clickjacking attack surface.

The directive accepts three values, though modern browsers have deprecated one:

  • DENY — Disallows the page from being displayed in a frame under any origin. This is the safest default for applications that never need to be embedded.
  • SAMEORIGIN — Allows framing only by pages sharing the exact same origin (scheme + host + port). Use this when your application needs to frame itself but should reject external embedding.
  • ALLOW-FROM uri — Permits framing only from the specified URI. This directive is deprecated in modern browsers and should be avoided in favor of Content Security Policy for granular origin control.

Architectural Placement Strategies

According to the Front-End-Checklist source analysis, you should implement X-Frame-Options as a baseline security measure enabled globally, with exceptions only for legitimate use cases like partner dashboards.

Configure the header at one of three architectural levels:

  1. Edge/Reverse Proxy (Nginx, Apache, Cloudflare) — Adding the header at the proxy level guarantees that all downstream services inherit protection without requiring application code changes.
  2. Application Server (Node.js/Express, Django, Rails) — Use this level when you need dynamic control, such as allowing framing for specific routes while denying it globally.
  3. Static File Hosts (S3, Netlify, Vercel) — Most static hosting providers support custom response headers via configuration files or UI settings.

Configuration Examples by Platform

Below are practical implementations for common environments. All examples set the header to DENY, which provides maximum protection by default.

Express.js (Node.js)

Create middleware to set the header globally, then apply it to all routes:

// middleware/secureHeaders.js
module.exports = (req, res, next) => {
  // Prevent clickjacking for every response
  res.setHeader('X-Frame-Options', 'DENY');
  next();
};

// In your main app file
const express = require('express');
const secureHeaders = require('./middleware/secureHeaders');
const app = express();

app.use(secureHeaders);           // Apply globally
// … define routes …
app.listen(3000);

For routes requiring different policies, override the header explicitly:

app.get('/embed', (req, res) => {
  res.setHeader('X-Frame-Options', 'SAMEORIGIN');
  res.sendFile('embed.html');
});

Nginx

Add the header directive to your server block or http context:


# Add to server block or http block

add_header X-Frame-Options "DENY" always;

To allow a specific trusted origin (noting that modern browsers prefer CSP):

add_header X-Frame-Options "ALLOW-FROM https://partner.example.com" always;

Apache

Enable the header module and configure it in your virtual host or .htaccess:

<IfModule mod_headers.c>
    Header always set X-Frame-Options "DENY"
</IfModule>

Netlify

Create a _headers file at the site root:


/*
  X-Frame-Options: DENY

Cloudflare

In the Cloudflare dashboard, navigate to Rules → Transform Rules → HTTP Response Header Modification:

  • Header name: X-Frame-Options
  • Action: Set
  • Value: DENY

Content-Security-Policy as Modern Alternative

While X-Frame-Options provides baseline protection, the Content Security Policy (CSP) frame-ancestors directive offers granular control and supersedes XFO in modern browsers:

Content-Security-Policy: frame-ancestors 'self' https://partner.example.com;

For backward compatibility with older browsers, you can send both headers, but prefer CSP frame-ancestors for new projects requiring multiple allowed origins.

Summary

  • X-Frame-Options prevents clickjacking by controlling whether browsers may render your page inside <iframe> elements, as documented in the Front-End-Checklist README.md at lines 602–605.
  • The DENY directive provides the strongest protection by blocking all framing, while SAMEORIGIN permits self-framing for applications that need it.
  • Configure headers at the reverse proxy or edge CDN level when possible to ensure universal coverage across all application endpoints.
  • Use ALLOW-FROM only when supporting legacy browsers, as modern implementations should utilize CSP frame-ancestors for URI-specific embedding permissions.
  • Reference RFC 7034 and Scott Helme's guidance, as linked in the Front-End-Checklist repository, for authoritative technical details on header behavior.

Frequently Asked Questions

What is the difference between DENY and SAMEORIGIN in X-Frame-Options?

The DENY directive blocks all framing attempts regardless of origin, preventing even your own site from embedding the page in iframes. The SAMEORIGIN directive restricts framing to pages sharing the identical scheme, host, and port, allowing your application to frame itself while rejecting external embedding attempts.

Is X-Frame-Options deprecated in favor of Content Security Policy?

X-Frame-Options is not officially deprecated, but the CSP frame-ancestors directive has replaced it as the modern standard for controlling iframe embedding. While you can use both headers for backward compatibility with older browsers, CSP offers superior granularity by allowing multiple specific origins rather than XFO's binary same-origin versus deny model.

Where is X-Frame-Options documented in the Front-End-Checklist repository?

The requirement appears in README.md at lines 602–605, where it is categorized as a medium-priority security item. The entry references Scott Helme's security guidance and RFC 7034 as implementation authorities, and the repository's CONTRIBUTING.md file explains how developers can propose enhancements to this security guidance.

Why doesn't ALLOW-FROM work in modern browsers?

The ALLOW-FROM directive is deprecated in most modern browsers including Chrome and Edge because it supports only a single URI and lacks the flexibility required by complex web architectures. Modern browsers ignore this directive in favor of the CSP frame-ancestors directive, which supports multiple origins and provides more robust clickjacking protection.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →