Development

HTTP Security Headers Checklist (with Copy-Paste Configs)

A handful of response headers block whole classes of attacks — clickjacking, MIME sniffing, protocol downgrades, much of XSS — at almost no cost. Here are the headers worth sending, safe starting values, and how to roll out the tricky one (CSP) without breaking your site.

Intermediate · 8 min read · Updated October 30, 2026

The checklist

HeaderSafe valueProtects against
Strict-Transport-Securitymax-age=31536000; includeSubDomainsHTTPS downgrade and cookie theft on public Wi-Fi
Content-Security-PolicyStart report-only (below)XSS, injected scripts, data exfiltration
X-Content-Type-OptionsnosniffBrowsers running uploads as scripts
CSP frame-ancestors'self' (or X-Frame-Options: SAMEORIGIN)Clickjacking
Referrer-Policystrict-origin-when-cross-originLeaking full URLs (tokens, IDs) to other sites
Permissions-Policycamera=(), microphone=(), geolocation=()Third-party scripts using device features

See which of these your site sends now, with a grade, in the Security Headers Checker.

HSTS: start short

Once a browser sees HSTS it refuses plain HTTP for the whole max-age. Make sure every subdomain works over HTTPS first (check certificates with the SSL Checker), start with max-age=300, then raise it to a year. Add preload and submit to the HSTS preload list only when you are sure — removal takes months.

Content-Security-Policy without breaking things

CSP lists where scripts, styles, images and connections may come from. Roll it out in report-only mode, which logs violations without blocking anything:

Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; report-uri /csp-report

Watch the browser console and your report endpoint for a week, add the sources you really use, then switch the header name to Content-Security-Policy. Avoid 'unsafe-inline' for scripts; use nonces or hashes for inline scripts you control. Build the policy source by source with the CSP Generator.

Configurations

Nginx (inside server; always keeps headers on error pages too):

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;

Apache (.htaccess, with mod_headers):

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
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=()"

Vercel (vercel.json):

{ "headers": [ { "source": "/(.*)", "headers": [
  { "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" },
  { "key": "X-Content-Type-Options", "value": "nosniff" },
  { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
] } ] }

Generate full server configs with the Nginx Config Generator or the .htaccess Generator.

Headers you can drop

X-XSS-Protection is obsolete — modern browsers removed the filter it controlled, and 0 is the recommended value if you send it at all. Expect-CT is deprecated. Hiding Server and X-Powered-By is good hygiene but not real protection.

Frequently asked questions

Which security headers are most important?
Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options: nosniff and frame-ancestors (or X-Frame-Options). Referrer-Policy and Permissions-Policy are quick wins.
Will a Content-Security-Policy break my site?
It can if you enforce it straight away. Start with Content-Security-Policy-Report-Only, fix what it reports, then enforce.
Is X-Frame-Options still needed?
CSP frame-ancestors replaces it in modern browsers. Sending both is fine for older browsers.

Keep reading