Clickjacking is an attack where another website loads your page in an invisible frame and tricks visitors into clicking buttons on it: a "Play" button that is really your "Delete account" or "Confirm payment". The defence is simple: tell browsers which sites may put your pages in a frame. This guide shows how to do that with the Content-Security-Policy: frame-ancestors header and the older X-Frame-Options header, on Apache, Nginx, PHP and WordPress.
Send Content-Security-Policy: frame-ancestors 'self' to allow framing only by your own site, or 'none' to block it completely. Also send X-Frame-Options: SAMEORIGIN or DENY for older browsers. On Domain India shared hosting, add both with a Header always set line in .htaccess: the servers run Apache with mod_headers loaded. Check the result with curl -I or your browser's developer tools.
1. How clickjacking works
- A visitor who is logged in to your site opens a page on the attacker's site.
- That page loads your page in an
iframe, made transparent and placed over a harmless-looking button. - The visitor clicks what they see, but the click lands on your page, with their session and cookies.
Anything a single click can do is at risk: changing settings, submitting a form, confirming an order, granting a permission. Your site's own code isn't at fault; the fix is to refuse to be framed by sites you don't trust.
2. The two headers
| Header | Values | Status in 2026 |
|---|---|---|
| Content-Security-Policy: frame-ancestors | 'none', 'self', or a list of allowed origins | The current standard; supported by all modern browsers |
| X-Frame-Options | DENY or SAMEORIGIN | Older, still honoured; useful as a fallback |
| X-Frame-Options: ALLOW-FROM | A single origin | Obsolete; modern browsers ignore it, so never rely on it |
When both headers are present, modern browsers follow frame-ancestors and ignore X-Frame-Options. Sending both costs nothing and covers old browsers too.
Choose the value by what your site needs:
'none'/DENY: nobody may frame your pages, including you. Best for admin areas, dashboards and checkout.'self'/SAMEORIGIN: only pages on your own domain may frame them. Use this if your site frames its own pages, as some page builders and CMS previews do.- A list of origins:
frame-ancestors 'self' https://partner.example.comallows named sites.X-Frame-Optionscan't express this, so rely on CSP.
frame-ancestors works only as an HTTP header. Browsers ignore it inside a meta tag.
3. Apache and .htaccess
Put this in the site's .htaccess file or the virtual host configuration:
<IfModule mod_headers.c>
Header always set Content-Security-Policy "frame-ancestors 'self'"
Header always set X-Frame-Options "SAMEORIGIN"
</IfModule>always adds the header to error responses and redirects as well. A .htaccess change applies on the next request; on your own server, run apachectl configtest and reload Apache after editing the main configuration.
If your site already sends a Content-Security-Policy header with other rules, add frame-ancestors to that header rather than sending a second one. Two CSP headers are both enforced, which can block things you didn't expect.
4. Nginx
On your own server, add the headers inside the server block and reload:
add_header Content-Security-Policy "frame-ancestors 'self'" always;
add_header X-Frame-Options "SAMEORIGIN" always;nginx -t && systemctl reload nginxOne trap: a location block that has any add_header of its own doesn't inherit the ones from the server block. Repeat the security headers there, or keep them in a shared snippet you include in both places.
5. PHP and WordPress
In PHP, send the headers before any output:
header("Content-Security-Policy: frame-ancestors 'self'");
header('X-Frame-Options: SAMEORIGIN');This is useful when only some pages need protection, but a server-level header is safer, because it also covers static files and pages that don't run your code.
WordPress already sends X-Frame-Options: SAMEORIGIN on its login and admin pages. For the public site, add the .htaccess lines from section 3, or use a security plugin that manages headers. Test the block editor and Customizer afterwards: they frame your own pages, so use 'self', not 'none'.
6. Test it
curl -sI https://yourdomain.com | grep -i -E "frame-options|content-security-policy"You should see both headers. You can also:
- open your browser's developer tools (F12), go to Network, reload, and read the response headers of the page;
- scan the site with a public security-header checker such as Mozilla's HTTP Observatory;
- make a local test file that frames your site and open it in a browser. With protection on, the frame stays empty and the console reports that framing was refused.
<iframe src="https://yourdomain.com" width="600" height="400"></iframe>If a header is missing on some pages, check for another .htaccess in a subfolder, an application that sets its own headers, or a caching layer serving a copy saved before the change.
7. Clickjacking is one layer
Framing headers stop this attack, but they work best alongside other basics:
SameSite=Lax or Strict are not sent in most cross-site requests.For HSTS, a full CSP and other headers, see Security headers explained.
8. Running this on Domain India
- Shared hosting (cPanel, DirectAdmin, Webuzo). The web server is Apache,
.htaccessis allowed, andmod_headersis loaded on all three (checked on our servers, 23 September 2026), so section 3 works as written. The servers don't add framing headers for you, so add them yourself. You can't reload Apache or edit its main configuration, and you don't need to. Don't usephp_valuelines in.htaccess: they cause a 500 error on our servers. - Testing on cPanel. A cache in front of Apache can serve a copy saved before your change for up to two hours. Add
?t=1to the URL when you test, for examplecurl -sI "https://yourdomain.com/?t=1". - Mistakes. A syntax error in
.htaccessgives a 500 error. Remove the last change and see Troubleshooting 500 Internal Server Error. - VPS. A Domain India VPS is self-managed with full root access, so the Apache and Nginx sections apply directly.
- 25 GB NVMe SSD Storage
- 50 GB Monthly Bandwidth
- 1 Website
- 10 Email Accounts
The card shows the live Domain India list price, excluding 18% GST.
What is clickjacking?
An attack where another site loads your page in a hidden frame and tricks visitors into clicking buttons on it, such as a delete, buy or confirm button, while they think they are clicking something else.
Should I use X-Frame-Options or Content-Security-Policy frame-ancestors?
Use frame-ancestors as the main control, because it is the current standard and can allow a list of sites. Also send X-Frame-Options with DENY or SAMEORIGIN as a fallback for older browsers.
Does X-Frame-Options ALLOW-FROM still work?
No. Modern browsers ignore ALLOW-FROM. To allow specific sites to frame your pages, use Content-Security-Policy frame-ancestors with a list of origins.
Can I set frame-ancestors in a meta tag?
No. Browsers ignore frame-ancestors in a meta tag. It must be sent as an HTTP response header from the server, .htaccess or your application.
How do I add X-Frame-Options on Domain India shared hosting?
Add Header always set lines for Content-Security-Policy and X-Frame-Options to the .htaccess file in your site's folder. The servers run Apache with mod_headers loaded, and the change applies on the next request.
Will blocking framing break my WordPress site?
Using 'none' or DENY can break the block editor preview and the Customizer, because they frame your own pages. Use 'self' and SAMEORIGIN instead.
Ready to harden your site? Add the headers, test them with curl -I, then work through Security headers explained. If something breaks, open a ticket with the URL and the change you made.
Apache-based shared hosting with .htaccess support, free SSL and PHP versions you choose in the control panel.
See cPanel hosting