Security Headers Worth Setting Today
Security headers are among the highest ratio of protection to effort available on a website. They're configuration, not code, and several of them shut down whole classes of attack.
Here they are in the order we'd add them.
Strict-Transport-Security
Tells browsers to only ever reach your site over HTTPS, even if someone types http:// or clicks an old link. It closes the window where a first insecure request can be intercepted.
Strict-Transport-Security: max-age=31536000; includeSubDomains
The caution: once set with a long max-age, browsers will refuse plain HTTP for your domain for that long. Make sure HTTPS works everywhere — including subdomains — before setting includeSubDomains. Start with a short max-age if you're unsure.
X-Content-Type-Options
X-Content-Type-Options: nosniff
Stops browsers from guessing a file's type and executing something as script that you served as data. One line, no downside, no reason to omit it.
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
Controls how much of the current URL is sent when a visitor clicks through to another site. The default leaks full paths — which on a members area or a search results page can leak more than you'd expect.
X-Frame-Options / frame-ancestors
Stops your site being embedded in an invisible iframe on someone else's page and used to trick visitors into clicking things (clickjacking).
Content-Security-Policy: frame-ancestors 'self'
The CSP form supersedes X-Frame-Options; sending both is fine for older clients.
Content-Security-Policy
The most powerful and the most work. It defines where scripts, styles, images, and connections may come from, which largely neutralizes injected script.
It's also the one most likely to break your site, because a typical business site loads from a dozen third parties.
Do it in stages:
- Deploy as
Content-Security-Policy-Report-Onlywith a reporting endpoint. - Watch what it would have blocked, for a couple of weeks.
- Add the legitimate sources.
- Then enforce.
Deploying a strict policy directly to production without the report-only phase is how people end up with a site that loads no images and a very confused afternoon.
Permissions-Policy
Declares which browser features the page may use — camera, microphone, geolocation. Denying what you don't need limits what an injected script or an embedded third party can ask for.
Permissions-Policy: camera=(), microphone=(), geolocation=()
How to apply them
On Netlify, a _headers file or a [[headers]] block. On Apache, .htaccess. On nginx, the server block. On a CDN, usually an edge rule — which has the advantage of applying regardless of what the origin does.
Check your work
Run your domain through a headers scanner after deploying. It takes seconds and tells you exactly what's present and what's missing.
Then check the site still works — particularly forms, embeds, and anything that loads from another domain. The whole exercise is an hour, and it's an hour that removes several standing risks permanently.