Clickjacking: X-Frame-Options vs frame-ancestors
How clickjacking works, why X-Frame-Options is legacy, the frame-ancestors directive that replaces it - and the one case you still want both.
Short answer
Prefer CSP frame-ancestors for modern browsers, and keep X-Frame-Options: DENY (or SAMEORIGIN) as a legacy companion. If nobody should embed your UI, say so in both places.
How clickjacking actually works
An attacker loads your page in a transparent iframe over a decoy UI. The victim thinks they click the decoy. They actually click Authorize, Delete, or Transfer on your origin. Framing controls are how you refuse that setup entirely.
Login pages, payment confirmations, and admin actions are the usual targets. If your UI can be framed by any origin, you are volunteering for this class of bug.
Modern control: frame-ancestors
CSP frame-ancestors is the current standard. frame-ancestors 'none' means no embedding. You can list trusted parent origins when a partner product must embed you - never use a wildcard for private apps.
Put the directive on the responses that matter: HTML documents, not only API JSON. CDNs that strip CSP on error pages are a common regression.
Legacy belt: X-Frame-Options
Keep X-Frame-Options: DENY (or SAMEORIGIN) alongside frame-ancestors so older clients still refuse framing. Supporting browsers prefer CSP when both are present; older ones still need the classic header.
SAMEORIGIN is for cases where you deliberately frame yourself. DENY is simpler when you never need frames at all.
Verify you actually closed it
After deploy, open a local HTML file that iframes your production URL. It should fail to render your UI. Your free security grade should flip the framing check to pass.
If either check still fails, the header is not on the response users get - fix the edge, not a README.
Config to copy
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
Paste carefully. Test on staging first if the setting can lock users out.
What to do this week
- Decide: never framed (DENY / none) or only same-origin.
- Ship CSP frame-ancestors and X-Frame-Options on the HTML responses.
- Prove with a local iframe test against production.
- Re-scan and screenshot the green framing check for the evidence folder.
If you do not need to be framed, refuse to be framed.
Update log (1)
2026-05-07Editorial form rewrite for length and uniqueness.
Sources + verification
Practical guidance based on mainstream browser behavior, common reverse-proxy configuration, and widely published RFCs and vendor docs. Verify on your own stack with curl, browser devtools, and a re-scan after each change.