The header that stops your site being framed for clickjacking
Here's something you can test on your own site in ten seconds, and most people have never tried it: can another website load your pages inside an invisible iframe and put their own buttons on top of yours? If you've never sent a frame-protection header, the answer is yes, and the attack that follows is called clickjacking.
It isn't theoretical and it isn't loud. The victim sees a perfectly normal page on some other site. Underneath, they're clicking yours.
How the overlay works
An attacker builds an ordinary-looking page. A prize wheel, a video, a "click to continue" gate. They load your real site inside an iframe on that page, then set its opacity to zero so it's completely invisible. Then they position their bait button exactly over a button on your framed page. The user clicks what they can see. The click lands on what they can't.
The dangerous part is that the framed page is genuinely yours, loaded in the victim's own browser, with the victim's own cookies. So if they're logged in to you, the click runs with their session. "Confirm payment." "Delete account." "Grant this app access." "Change email." Any single-click action you expose to a logged-in user becomes a click the attacker can steal by lining up their bait over it. The user never typed anything suspicious or visited a phishing domain. They clicked a button on a page that looked harmless.
A composite you can picture
Say you ship a settings page with a one-click "Disable two-factor" toggle, because it's convenient. An attacker frames that page invisibly, overlays it with a "Skip ad" button, and seeds the link wherever your users hang out. Anyone who's logged in and clicks "Skip ad" has just turned off their own 2FA without seeing a thing. The action succeeded, the session was real, your server logged a normal authenticated request. Nothing in your logs looks wrong, because nothing technically was, except that the click came through a frame you should never have allowed.
How to check
You don't need anything but a browser.
- Save a tiny HTML file locally with one line:
<iframe src="https://yoursite.com" width="800" height="600"></iframe>. Open it. - If your site renders inside the frame, you have no protection. If you see a blank box or a refusal message, a header stopped it.
- Or read the headers directly:
curl -sI https://yoursite.com | grep -iE 'x-frame-options|content-security-policy'. You're looking for eitherX-Frame-Optionsor a CSPframe-ancestorsdirective.
Whether your page can be framed is something a stranger can determine without logging in, which is exactly why SurfaceCheckr can tell you in the same breath. We request your homepage from outside, read the response headers, and report whether framing is restricted. What we can't do is sit inside your app and rank your one-click actions by blast radius, that's not what a passive external scan sees. So we flag the page as frameable and leave you to assume the attacker lines their bait up over your worst button, because they will.
The fix is one header, with a catch
Two headers do this job, and the modern one is part of CSP. Send frame-ancestors in your Content-Security-Policy, and keep X-Frame-Options alongside it for older browsers.
# nginx: no framing rule at all,
# so any site can iframe these pages
server {
listen 443 ssl;
server_name yoursite.com;
# ...no frame headers
}The catch is the honest one: if any part of your product is meant to be embedded, an in-app widget, an OAuth dialog, an embeddable report, blanket DENY will break it. Use frame-ancestors 'self' to allow your own pages, or list the exact origins you trust. Don't reach for the old ALLOW-FROM value of X-Frame-Options; browsers dropped it, and frame-ancestors is where allowlisting lives now.
This header travels in the same response as your other security headers, so set it in the same pass that you tighten a CSP off unsafe-inline. And since clickjacking only pays off against a logged-in session, it's worth confirming your session cookies use SameSite and HttpOnly at the same time.
Write that one-line iframe file and open it against your own domain right now. If your page shows up inside the box, so does the attacker's button.
Find it before someone else does.
Paste your domain. The grade and issue count are free, and you'll see in a couple of minutes exactly what's reachable from outside.