HTTP Security Headers: The Complete Checklist with Real Examples
If you have ever run a security scan on your own site, you have seen the list: Content-Security-Policy missing, Strict-Transport-Security missing, X-Content-Type-Options missing. Each of these is an HTTP security header — a one-line instruction your server sends with every response that tells browsers how to behave. Setting them correctly closes entire attack classes. This guide explains each header, shows realistic values, and how to audit any site instantly with the free HTTP Header Inspector tool.
Why headers matter more than ever
Modern browsers enforce security at the header level. A perfectly coded application can still be framed by a phishing site, downgraded to plain HTTP by an attacker on the same network, or shipped with an unwanted script — unless headers say otherwise. Auditors, penetration testers and even browsers themselves treat missing headers as findings, and search engines increasingly favor sites that set them.
Strict-Transport-Security (HSTS)
HSTS tells browsers: once you have seen this header, never use plain HTTP for this domain again — even if the user types http:// or clicks an HTTP link.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
max-age— how long the rule sticks (one year here). Browsers remember it.includeSubDomains— every subdomain is covered, not just the main domain.preload— signals eligibility for the Chrome/Firefox HSTS preload list.
Start with a short max-age (say 300) while testing, then raise it. Once you send a long max-age, you are committed — fixing it requires waiting out the cache.
Content-Security-Policy (CSP)
CSP is the strongest anti-injection defense in the header toolbox. It whitelists where scripts, styles, frames and other resources may come from. A strict policy renders injected <script> tags inert.
Content-Security-Policy: default-src 'self'; script-src 'self' https://pagead2.googlesyndication.com; object-src 'none'; frame-ancestors 'self'; upgrade-insecure-requests
Roll out in report-only mode first:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
Watch the reports, tune the policy, then flip to enforcing. CSP has a reputation for complexity, but a default-src 'self' baseline with a few explicit exceptions covers most sites.
X-Frame-Options and frame-ancestors
These stop other sites from embedding yours in an <iframe> — the core of clickjacking. DENY forbids framing entirely; SAMEORIGIN allows your own pages to frame you.
X-Frame-Options: DENY
In CSP, frame-ancestors 'none' is the modern equivalent. Send both: older browsers only honor the classic header.
X-Content-Type-Options
Browsers historically "sniff" content types and will happily execute an uploaded file that was served as text/plain. This header turns sniffing off:
X-Content-Type-Options: nosniff
One line, zero downside for correctly configured sites, real protection against certain upload and cross-site scripting attacks.
Referrer-Policy
Controls how much of your URL is leaked in the Referer header when users click outbound links. strict-origin-when-cross-origin is today's sensible default: full URL stays on your own site, only the origin leaves it.
Referrer-Policy: strict-origin-when-cross-origin
For sites handling sensitive paths, same-origin or no-referrer leak nothing at all.
Permissions-Policy
The newest header of the family: it disables powerful browser features (camera, microphone, geolocation, payment APIs) for your pages and any embedded third parties.
Permissions-Policy: camera=(), microphone=(), geolocation=()
Empty parentheses mean nobody may use this feature. If your site never uses the camera, disabling it removes an entire class of abuse.
A realistic audit example
Running the HTTP Header Inspector against example.com returns something like:
- Strict-Transport-Security — present, one year — pass.
- Content-Security-Policy — missing — add a report-only policy this week.
- X-Content-Type-Options — present — pass.
- Referrer-Policy —
strict-origin-when-cross-origin— pass. - Permissions-Policy — missing — add a minimal deny-list.
Most production sites score somewhere in that range. The headers are cheap to add — usually one line in next.config.ts under headers(), or one line per header in your host's edge config — and each one is a genuine security improvement.
Where to set headers in Next.js
In next.config.ts:
async headers() {
return [{
source: '/(.*)',
headers: [
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'X-Frame-Options', value: 'DENY' },
],
}];
}
Deploy, then re-run the inspector to confirm every header arrives intact through CDNs and edge caches.
Frequently asked questions
Do security headers slow the site down?
No. They add a few dozen bytes per response and are enforced by the browser with no extra round trips.
Is X-Frame-Options obsolete?
Not yet. Modern browsers prefer CSP frame-ancestors, but older browsers still read only X-Frame-Options, so sending both remains best practice.
What is the first header to add?
X-Content-Type-Options: nosniff — one line, no breakage risk. Then HSTS with a short max-age, then CSP in report-only mode.
Can headers break my site?
CSP can, if it blocks scripts your page actually needs. That is exactly why report-only mode exists: observe, tune, enforce.
Audit your site now: paste any URL into the HTTP Header Inspector for an instant, private header audit — and check where a domain's traffic actually lands with DNS Lookup.