Defending Against Clickjacking with X-Frame-Options
Clickjacking, also known as a “UI Redress Attack”, is a malicious technique where an attacker tricks a user into clicking on a button or link on another page, when the user actually intended to click on the overlay page of a trusted website.
Implementing the X-Frame-Options header and CSP frame-ancestors directive is the primary defense against clickjacking.
The Mechanics of a Clickjacking Attack
In a clickjacking attack, the attacker does the following:
- Creates an innocent-looking website (e.g. “Get Free Gift Cards”).
- Embeds your legitimate website (such as your login page or a bank transfer page) inside a transparent
<iframe>overlaid directly on top of the fake site. - Positions the transparent iframe so that a high-value button (like “Transfer Funds” or “Delete Account”) aligns exactly with an innocent button on the fake site (like “Click here to win!”).
- The user, thinking they are clicking the “Click here to win!” button, actually clicks the invisible button on your legitimate site inside the iframe.
If your site allows framing and the user is currently logged in (authenticated via cookies), the browser executes the action using the user’s active session.
Defensive Strategy 1: The X-Frame-Options Header
Historically, the X-Frame-Options HTTP response header was introduced to specify whether a browser should be allowed to render a page in an <iframe>, <frame>, <embed>, or <object>.
Header Configurations
The header supports three directives:
# Option 1: Completely prevent any framing of this page
X-Frame-Options: DENY
# Option 2: Only allow pages on the same domain to frame this page
X-Frame-Options: SAMEORIGIN
# Option 3: Only allow the specified origin to frame this page (Legacy, poorly supported)
X-Frame-Options: ALLOW-FROM https://trustedpartner.com
DENY: This is the recommended setting for almost all pages, especially login panels, payment flows, and settings dashboards.SAMEORIGIN: Use this if you need to frame your own pages within other pages of the same website.
Defensive Strategy 2: CSP frame-ancestors (Modern Standard)
While X-Frame-Options is widely supported by legacy browsers, modern best practice dictates using the frame-ancestors directive in your Content Security Policy (CSP).
frame-ancestors is much more flexible because it supports multiple specific domains and wildcards, resolving the limitations of the old ALLOW-FROM directive:
# Block all framing (equivalent to DENY)
Content-Security-Policy: frame-ancestors 'none';
# Allow framing only by the same origin (equivalent to SAMEORIGIN)
Content-Security-Policy: frame-ancestors 'self';
# Allow framing by specific trusted external domains
Content-Security-Policy: frame-ancestors 'self' https://trustedpartner.com https://*.anotherpartner.com;
[!IMPORTANT] Precedence Rules: If both
X-Frame-OptionsandContent-Security-Policy: frame-ancestorsare present on a page, modern browsers will ignoreX-Frame-Optionsin favor of the CSPframe-ancestorsdirective. However, you should still ship both headers to ensure legacy browsers (such as Internet Explorer) remain protected.
How to Configure Your Server
Nginx Configuration
# Prevent framing completely
add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "frame-ancestors 'none';" always;
Apache Configuration
# Prevent framing completely
Header always set X-Frame-Options "DENY"
Header always set Content-Security-Policy "frame-ancestors 'none';"
Sources & Standards
- IETF RFC 7034: HTTP Header Field X-Frame-Options - Explains the semantics, history, and integration of the X-Frame-Options header.
- OWASP: Clickjacking Defense Cheat Sheet - Comprehensive development standards for clickjacking protection, frame breaking, and frame-ancestors.
- Mozilla MDN: CSP: frame-ancestors - Technical details on modern browser implementation of frame-ancestors.
How Vioro monitors this
Vioro audits your response headers to verify that X-Frame-Options (or CSP frame-ancestors) is present and correctly set to DENY or SAMEORIGIN, ensuring attackers cannot frame your login panels or checkout flows.