Missing X-Frame-Options (clickjacking)

What it is

Your site sends neither the X-Frame-Options header nor a CSPframe-ancestors directive. Without them, anyone can embed you in an <iframe> on a site they control.

Why it’s a problem

The attack is called clickjacking. The attacker builds an ordinary-looking page, loads your site inside an iframe, makes that iframe invisible with a CSS trick, and places a “Win an iPhone” button on top. The visitor clicks — but really they clicked “Delete account” on your site, where they’re logged in.

Practical scenarios:

How to fix it

There are two headers — you can send both:

X-Frame-Options (older, supported by every browser)

X-Frame-Options: DENY
# or
X-Frame-Options: SAMEORIGIN

DENY — nobody may embed you in an iframe, not even you.
SAMEORIGIN — only your own domain may embed you in an iframe.

CSP frame-ancestors (more modern, more granular)

Content-Security-Policy: frame-ancestors 'none';
# or:
Content-Security-Policy: frame-ancestors 'self';
# or with an allowlist:
Content-Security-Policy: frame-ancestors 'self' https://partner.example.cz;

When you have a CSP, frame-ancestors takes precedence over X-Frame-Options.

Specific configuration

nginx:

add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "frame-ancestors 'none'" always;

Apache:

Header always set X-Frame-Options "DENY"
Header always set Content-Security-Policy "frame-ancestors 'none'"

When NOT to use DENY?

Sometimes a site genuinely needs to be inside an iframe — on your own e-shop (an embedded widget), in a partner portal, in a white-label solution. In that case, don’t use DENY; instead set a specific allowlist via frame-ancestors.

References