HTTP Security Headers Checklist with Secure Examples
HTTP security headers add browser-enforced boundaries around a web application. They cannot repair vulnerable code, but they can reduce exploitability and make unsafe behavior explicit. Start by inspecting the final response—including redirects—with the HTTP Headers analyzer, then test changes in a staging environment.
A practical baseline
This Nginx example is a starting point, not a universal copy-and-paste policy:
add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self'; upgrade-insecure-requests" always;
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;
Adapt each directive to the application's resources and deployment model. A restrictive header that breaks authentication or payment flows will likely be removed under pressure; roll out deliberately.
Content-Security-Policy
CSP limits where scripts, styles, frames, and other resources may come from. Avoid broad allowances such as *, 'unsafe-inline', and 'unsafe-eval'. A nonce-based application might send:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-r4nd0mPerResponse'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
Generate an unpredictable nonce for every response and place it only on intended script elements. Do not use the illustrative value above. Begin with Content-Security-Policy-Report-Only to discover violations, but remember report-only mode does not block anything. Treat reports as potentially sensitive telemetry and rate-limit their endpoint.
Strict-Transport-Security
HSTS tells a browser to use HTTPS for future requests:
Strict-Transport-Security: max-age=31536000; includeSubDomains
HSTS only applies after HTTPS: browsers ignore it over plain HTTP, and a first visit is protected only when HTTPS is already used or the domain is preloaded. Add includeSubDomains only when every current and future subdomain supports HTTPS. Increase max-age gradually, and understand the long recovery period before considering preload. Check the deployed certificate chain and hostname with the certificate viewer.
Content type, framing, and referrers
X-Content-Type-Options: nosniff tells browsers not to reinterpret declared resource types. Send accurate Content-Type values alongside it.
Prefer CSP's frame-ancestors to control who may embed a page. X-Frame-Options: DENY or SAMEORIGIN is a useful legacy fallback, but it is less expressive:
Content-Security-Policy: frame-ancestors 'self' https://portal.example.test
Referrer-Policy: strict-origin-when-cross-origin keeps full paths on same-origin requests while generally limiting cross-origin referrers to the origin. Use no-referrer if even origins are too sensitive.
Cap browser capabilities
Permissions Policy disables capabilities the page does not need:
Permissions-Policy: camera=(), microphone=(), geolocation=(), usb=()
Enable a feature only for the origins and frames that require it. Also consider cross-origin isolation headers—COOP, COEP, and CORP—when an application genuinely needs isolation features. They can break popups, embedded assets, and third-party integrations, so they are not a blind baseline.
Cookies and API responses
Headers are only part of the response. Session cookies should normally use Secure, HttpOnly, and an intentional SameSite value:
Set-Cookie: session=opaque-value; Path=/; Secure; HttpOnly; SameSite=Lax
Never place a real session value in documentation. For APIs, configure CORS to the exact origins, methods, and headers needed; CORS is not authentication. Sensitive responses should also use an appropriate Cache-Control, such as no-store when storage is unacceptable.
Review checklist and mistakes
Inspect the initial URL, redirects, HTML, errors, and cached/CDN responses. Confirm headers are not duplicated with conflicting values. Test CSP without relying only on scanners, and verify that third-party scripts are truly necessary. Common mistakes include setting HSTS on HTTP, copying a CSP that permits everything, allowing credentials with a reflected origin, and believing headers replace output encoding, CSRF defenses, dependency updates, or authorization.
Version the intended policy with the application, monitor browser reports, and recheck after proxy or CDN changes. Security headers work best as tested configuration rather than a one-time score.