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.
The checklist
| Header | Safe value | Protects against |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | HTTPS downgrade and cookie theft on public Wi-Fi |
Content-Security-Policy | Start report-only (below) | XSS, injected scripts, data exfiltration |
X-Content-Type-Options | nosniff | Browsers running uploads as scripts |
CSP frame-ancestors | 'self' (or X-Frame-Options: SAMEORIGIN) | Clickjacking |
Referrer-Policy | strict-origin-when-cross-origin | Leaking full URLs (tokens, IDs) to other sites |
Permissions-Policy | camera=(), 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.