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

> Learn how to configure X-Frame-Options headers to prevent clickjacking attacks. Implement DENY or SAMEORIGIN for robust front-end security.

- Repository: [David Dias/Front-End-Checklist](https://github.com/thedaviddias/Front-End-Checklist)
- Tags: how-to-guide
- Published: 2026-03-02

---

**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`](https://github.com/thedaviddias/Front-End-Checklist/blob/main/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:

```js
// 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:

```js
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:

```nginx

# 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):

```nginx
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`:

```apache
<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:

```http
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`](https://github.com/thedaviddias/Front-End-Checklist/blob/main/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`](https://github.com/thedaviddias/Front-End-Checklist/blob/main/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`](https://github.com/thedaviddias/Front-End-Checklist/blob/main/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.