Security Headers for WordPress, and What Each One Actually Does
Security headers tell the browser how to treat your pages. They are cheap to add and several are genuinely useful. One of them will break your site if you apply it without testing, so the order here runs from safe to delicate.
The short version
- Four of the six are safe to set immediately.
- Content-Security-Policy is powerful and breaks things. Use report-only first.
- Set them at the server or CDN level, not in a plugin.
- HSTS is effectively permanent. Understand it before enabling.
The safe four
| Header | Protects against | Risk |
|---|---|---|
| X-Content-Type-Options | MIME-type sniffing attacks | None |
| X-Frame-Options | Clickjacking via framing | Breaks legitimate embedding |
| Referrer-Policy | Leaking URLs to third parties | Minimal |
| Permissions-Policy | Unwanted access to camera, mic, geolocation | Breaks features that need them |
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
If your site is legitimately embedded in an iframe by a partner, use a Content-Security-Policy frame-ancestors directive instead of X-Frame-Options, which allows a specific list.
HSTS: effective and effectively permanent
Strict-Transport-Security tells browsers to refuse plain HTTP for your domain for a stated period. It is a genuine improvement and it is close to irreversible, because browsers remember it for the full max-age.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Watch out
Do not set includeSubDomains unless every subdomain, including internal ones, has a valid certificate. Start with a short max-age such as 300 seconds, confirm nothing breaks, then raise it.
Content-Security-Policy: the one that breaks things
CSP restricts where scripts, styles, images and fonts may load from. It is the strongest header available and the most likely to break a WordPress site, because plugins and ad networks load resources from hosts you did not anticipate.
Always start in report-only mode, which reports violations without blocking:
add_header Content-Security-Policy-Report-Only
"default-src 'self'; script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;
font-src 'self' data:;" always;
Run that for a week, collect the violations, and widen the policy to cover the resources you legitimately use. Only then switch to the enforcing header.
On a site running display advertising, a strict CSP is often impractical because ad networks load from many rotating hosts. Decide early whether the trade is worth it for your site.
Where to set them
Server configuration or CDN edge rules, not a plugin. A plugin sets headers after PHP runs, which means static assets served directly by the web server do not get them, and the headers disappear entirely if the plugin is deactivated.
Verifying
curl -sI https://example.com | grep -iE 'strict-transport|x-frame|content-security|referrer|permissions|x-content'
Common questions
Will these improve my search rankings?
Not directly. HTTPS is a signal; these headers are not. They protect your users, which is reason enough.
Can I set CSP on a site with AdSense?
You can, but the policy becomes broad enough that much of the benefit is lost. Many publishers reasonably skip CSP for this reason.
What if HSTS causes a problem?
With a short max-age you simply wait it out. With a year-long max-age, affected browsers will refuse HTTP for a year, which is why starting short matters.
Sumit
Writes everything on TechMozz.