← All guides
Low

The other security headers: small settings, real protection

Referrer-Policy, Permissions-Policy and X-Content-Type-Options in plain English — what each one quietly protects you from.

7 minute read · Browser protections

The short version

Every time your website sends a page, it also sends a handful of invisible "headers" — short instructions to the browser. A few of them exist purely for security. None of these three is dramatic on its own, but each closes a door that attackers have used, they cost nothing, and together they are a sign of a site that is looked after. This guide covers X-Content-Type-Options, Referrer-Policy and Permissions-Policy, plus cache headers on sensitive pages.

X-Content-Type-Options: stop the browser guessing

When your server sends a file, it labels what kind of thing it is — an image, a stylesheet, a script. Old browser behaviour was to *guess* if the label looked wrong, by looking at the file's contents. That sounds helpful, but it opened a hole: an attacker who could upload a harmless-looking file to your site (a profile picture, a PDF attachment) could craft it so the browser "guessed" it was actually a script and ran it.

The header X-Content-Type-Options: nosniff simply says: trust the label, never guess. There is exactly one correct value, it has no side effects on a properly configured site, and there is no reason not to send it.

X-Content-Type-Options: nosniff

Referrer-Policy: what you tell other sites about your visitors

When someone clicks a link on your site to another site, their browser tells the destination where they came from — the "referrer". By default that can include the *full address* of the page they were on. If that address contains anything private — a password-reset token, an order number, a search they typed, a customer name in the URL — you have just leaked it to whichever site they clicked through to, and to every advert and analytics script on that site.

The Referrer-Policy header controls how much is shared. The sensible default for almost every site is:

Referrer-Policy: strict-origin-when-cross-origin

That means: when a visitor goes to another site, only tell it *which site* they came from (yourbusiness.co.uk), not which page. Within your own site, the full address is still shared so your own analytics keep working. Modern browsers now use this as their built-in default, but setting it explicitly covers older browsers and makes your intent clear. Avoid unsafe-url, which shares everything, and no-referrer-when-downgrade, the old permissive default.

Permissions-Policy: switching off features you do not use

Browsers can give web pages access to powerful things: the camera, the microphone, the visitor's location, payment APIs, motion sensors. Each of those is a thing a malicious script injected into your page — or a dodgy third-party widget you embedded — could try to use.

Permissions-Policy lets you say up front which of these your site needs. For most business sites the answer is "none of them", so you turn them all off:

Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()

Each () means "nobody, not even my own page". If you genuinely use one — say a store locator that asks for location — allow it for your own origin only: geolocation=(self). Embedded third-party pages (iframes) are denied these features unless you explicitly grant them, which is exactly what you want.

Cache headers on pages that should not be remembered

Browsers and intermediate servers store copies of pages to make the web faster. For a public homepage that is good. For a page showing someone's account details, order history or a password-reset form, it is a problem: the page can be served to the *next* person on a shared computer, or kept in a proxy where it should not be.

Pages with personal or session-specific content should send:

Cache-Control: no-store

Most frameworks and e-commerce platforms do this automatically for logged-in pages. We flag the case where a page that sets a session cookie is also marked as publicly cacheable — a combination that should not happen.

Setting them all at once

On Apache or LiteSpeed shared hosting, these lines in .htaccess cover the three headers for the whole site:

Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"

On Cloudflare they go in Rules → Transform Rules → Modify Response Header, which has the advantage of covering every page regardless of what the origin server does. On WordPress, security plugins expose these as toggles. On nginx, use add_header in the server block with the always flag.

Unlike a Content Security Policy, these three headers are safe to add in one go. The only one that can affect a feature is Permissions-Policy, and only if you disable something your site really uses — so check any map, camera or payment widget afterwards.

Common questions

Are these headers going to make a measurable difference to my security?
Individually they are small. Collectively they remove a set of known attack techniques, they are checked by every security scanner and insurer questionnaire, and they take ten minutes. Few security tasks have a better effort-to-benefit ratio.
I set these in .htaccess but VigilScan still says they are missing.
Three common causes: the hosting does not have mod_headers enabled (ask your host); Cloudflare or another proxy is stripping them; or a cached copy of your page is being served. Check the live response headers in your browser's developer tools (Network tab) to see what is really being sent.
What about X-XSS-Protection?
It is obsolete. Modern browsers removed the feature it controlled, and in some cases it introduced vulnerabilities of its own. Do not add it; a Content Security Policy is the real protection against cross-site scripting.

Not sure if this affects your site?

Run a free check — it takes about 90 seconds and tells you exactly where you stand.

Check my website