HTTP security headers are short instructions a server adds to its responses that tell the browser to turn on specific protections: which scripts may run, whether the page may be framed, whether to trust declared content types, and how much referrer data to leak. They are among the cheapest, highest-leverage defences a website has, because the browser enforces them for you.
Most headers cost one line of server configuration and defend against a whole class of attack. The catch is that they are opt-in: a browser assumes the permissive default unless the server says otherwise. This guide walks through each header that matters in 2026, the attack it blocks, and a value you can paste in and adjust.
The headers that matter, ranked
| Header | Blocks | Priority |
|---|---|---|
| Content-Security-Policy | Cross-site scripting, injection, some clickjacking | High |
| Strict-Transport-Security | SSL stripping, HTTP downgrade | High |
| X-Content-Type-Options | MIME sniffing attacks | High |
| X-Frame-Options / frame-ancestors | Clickjacking | High |
| Referrer-Policy | URL and token leakage via Referer | Medium |
| Permissions-Policy | Unwanted camera, mic, geolocation access | Medium |
| Cross-Origin-Opener-Policy | Cross-window attacks, enables isolation | Medium |
Content-Security-Policy
CSP is the single most powerful header and the hardest to get right. It declares where scripts, styles, images and other resources may load from, and a strict policy neutralises most cross-site scripting even if an injection slips through. Because it deserves proper treatment, we cover authoring, nonces and rollout in the dedicated Content Security Policy guide. A modern nonce-based starting point:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-r4nd0m'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
A missing policy is flagged by our CSP check, and a present-but-weak one by the weak-directives check.
Strict-Transport-Security (HSTS)
HSTS tells the browser to only ever contact your site over HTTPS, closing the window an attacker uses to strip encryption. The recommended value:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
That is a two-year policy covering every subdomain and declaring intent to join the preload list. Do not add preload until you are certain every subdomain serves HTTPS, because it is hard to reverse. HSTS has enough depth to warrant its own explainer, and our HSTS check verifies it.
X-Content-Type-Options
Browsers sometimes guess ("sniff") a response's type when the declared type looks wrong, and that guess can turn an uploaded image into executable script. One value stops it:
X-Content-Type-Options: nosniff
There is no downside if your server sends correct Content-Type headers, which it should. It is cheap, universal and checked by our nosniff check.
Framing control: X-Frame-Options and frame-ancestors
Clickjacking loads your page invisibly inside an attacker's site and steals clicks. The modern control is the CSP frame-ancestors directive; the legacy control is X-Frame-Options. The nuance in 2026 is that frame-ancestors supersedes the older header, but some older clients and embedded webviews still honour only X-Frame-Options, so sending both is the pragmatic choice:
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
Use SAMEORIGIN instead of DENY if your own pages need to frame each other. The full attack and its defences are in clickjacking explained; the framing check reports gaps.
Referrer-Policy
By default browsers send the full URL of the current page in the Referer header of outgoing requests, which can leak session tokens or private paths to third parties. A sane, private default:
Referrer-Policy: strict-origin-when-cross-origin
This sends the full URL to your own origin, only the origin (not the path) to other HTTPS sites, and nothing when downgrading to HTTP. The Referrer-Policy check confirms it is set.
Permissions-Policy
Permissions-Policy (the successor to Feature-Policy) lets you switch off powerful browser features your site does not use, so injected code cannot abuse them. Deny what you do not need:
Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=()
Each empty allowlist means "no origin, including me, may use this." Our Permissions-Policy check looks for it. Only deny features you genuinely do not use; if your site legitimately needs the camera for a video call, list your own origin rather than blocking it. The point is to shrink the attack surface, not to break functionality.
The cross-origin isolation headers
A newer family of headers governs how your page relates to other origins in the browser's process model, and they matter if you use powerful features like SharedArrayBuffer or high-resolution timers, or simply want to reduce the reach of a compromised third-party window. Cross-Origin-Opener-Policy (COOP) severs the link between your page and any window that opened it or that it opens, preventing cross-window scripting tricks:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy (CORP) lets a resource declare who may embed it, and Cross-Origin-Embedder-Policy (COEP) lets a document require that every resource it loads opts in. Together, COOP and COEP put a page into a "cross-origin isolated" state that the browser treats as safer. These are more specialised than the core four, and most sites should adopt them only when they understand the embedding they will break, but on a sensitive application they close genuine gaps. They round out the set that a full header audit reports.
How the headers work together
The headers are not independent switches; they overlap deliberately, and understanding the overlap prevents both gaps and wasted effort. Clickjacking, for instance, is addressed by both X-Frame-Options and CSP frame-ancestors, and the CSP directive is authoritative where both are present. Script injection is nominally the job of the retired X-XSS-Protection, but the real defence is CSP script-src. Transport is enforced by HSTS but only means anything once your TLS configuration is sound in the first place. Reading the set as a system, rather than a checklist to maximise, keeps you from, say, agonising over X-XSS-Protection while shipping a CSP with unsafe-inline that undoes the protection you cared about.
A second systemic point: a header is only as good as its coverage. A CSP that applies to your main pages but not to a legacy subdomain, or headers that appear on 200 responses but vanish on the 404 page an attacker probes, leave exactly the holes an attacker looks for. Consistency across every response and every host is worth more than any single perfect header on your homepage.
X-XSS-Protection. The old auditor it controlled has been removed from major browsers, and in some cases it introduced its own vulnerabilities. If you set it at all, set X-XSS-Protection: 0. Rely on CSP for script-injection defence instead.Setting them once, at the right place
Set headers in one place so every response is covered, not per-page where a route will be forgotten. In nginx:
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
In Apache:
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
In Express, one middleware covers your app:
app.use((req, res, next) => {
res.set('X-Content-Type-Options', 'nosniff');
res.set('Referrer-Policy', 'strict-origin-when-cross-origin');
next();
});
always keyword in nginx and Apache matters: without it the header is dropped on error responses like 404 and 500, which are exactly the pages an attacker probes.Verify, do not assume
Headers are easy to get subtly wrong: a typo, a directive that silently disables the policy, or a rule that applies to one virtual host but not another. After any change, confirm the live response. Our security headers checker grades every header on a URL, and the broader website scanner puts them in context with TLS, cookies and exposed files. Headers are the first thing we look at in the website security hub because they buy so much safety for so little work.
A closing perspective on priorities. It is tempting, once you start setting headers, to chase a perfect score on every checker, adding obscure headers and tightening every directive until something breaks. That is effort misallocated. The realistic ranking is: get HTTPS and HSTS right, since transport underpins everything; deploy a genuinely strict CSP, because it defends against the highest-impact web attack; add nosniff and a framing control, which are effectively free; then set Referrer-Policy and Permissions-Policy as sensible hygiene. The cross-origin isolation headers come last, and only when you have a concrete reason. Beyond that, the marginal header rarely changes your real exposure, and the time is better spent confirming the important ones apply everywhere, on every host and every response code, than on collecting rarely-tested extras. Coverage of the essentials beats a long list with gaps in it, every time.
Finally, remember that headers are declarations the browser enforces, which means they protect users on modern browsers and do nothing for a determined attacker probing your server directly. That is not a weakness; it is the correct division of labour. Headers harden the client side of the relationship, telling each visitor's browser to refuse framing, reject sniffed content types and run only blessed scripts. Server-side controls, input validation, access checks, patching, harden the other side. A site needs both, and reading a header report as a complete security assessment is the one misuse to avoid. The headers in this guide are a high-return first layer, not the whole defence, and their value is realised only when they sit on top of a server that is itself sound.