HTTP Security Headers Reference
Every security header explained with recommended values, server configuration examples, and common misconfigurations to avoid.
Why Security Headers Matter
HTTP security headers are response headers that instruct the browser to enable or enforce security mechanisms. They are a zero-cost defense layer — adding a few lines to your server configuration can prevent entire classes of attacks including XSS, clickjacking, MIME confusion, protocol downgrade, and information leakage. Despite being easy to implement, the majority of websites still fail to set critical security headers.
Strict-Transport-Security (HSTS)
HSTS forces the browser to use HTTPS for all future requests to your domain, preventing protocol downgrade attacks and cookie hijacking over HTTP.
Recommended value:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
max-age=31536000 tells the browser to remember the HTTPS-only policy for one year. includeSubDomains applies the policy to all subdomains. preload signals eligibility for browser HSTS preload lists. Start with a short max-age (e.g., 300) during testing, then increase to one year after confirming everything works.
Nginx: add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Apache: Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options
Prevents MIME-type sniffing, which can lead to XSS when browsers interpret non-script files as executable JavaScript.
Recommended value:
X-Content-Type-Options: nosniff
There is only one valid value. This header is simple and has no compatibility concerns. Set it on every response.
Nginx: add_header X-Content-Type-Options "nosniff" always;
Apache: Header always set X-Content-Type-Options "nosniff"
X-Frame-Options
Controls whether your page can be embedded in an iframe, preventing clickjacking attacks where an attacker overlays your page with a transparent frame to steal clicks.
Recommended value:
X-Frame-Options: DENY
DENY prevents all framing. SAMEORIGIN allows framing by pages on the same origin. Avoid ALLOW-FROM as it has inconsistent browser support. For more flexible control, use the CSP frame-ancestors directive alongside this header.
Nginx: add_header X-Frame-Options "DENY" always;
Apache: Header always set X-Frame-Options "DENY"
Referrer-Policy
Controls how much referrer information is included in the Referer header when navigating away from your site. Prevents leaking sensitive URL paths, query parameters, and session tokens to third-party sites.
Recommended value:
Referrer-Policy: strict-origin-when-cross-origin
This sends the full URL for same-origin requests, the origin only for cross-origin HTTPS requests, and nothing for HTTPS-to-HTTP transitions. Other useful values: no-referrer (maximum privacy), same-origin (referrer only for same-origin navigation).
Nginx: add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Apache: Header always set Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy (formerly Feature-Policy)
Controls which browser features and APIs can be used on your page. Disabling unused features reduces your attack surface and prevents malicious scripts from accessing sensitive APIs.
Recommended value:
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
The empty parentheses () disable the feature entirely. Use (self) to allow the feature for your origin only. Available features include: accelerometer, autoplay, camera, clipboard-read, clipboard-write, fullscreen, geolocation, gyroscope, magnetometer, microphone, payment, usb, and more.
Nginx: add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
Apache: Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"
Cross-Origin Headers
Cross-Origin-Embedder-Policy (COEP): require-corp ensures all cross-origin resources explicitly grant permission to be loaded. Required for enabling SharedArrayBuffer and high-resolution timers.
Cross-Origin-Opener-Policy (COOP): same-origin isolates your browsing context from cross-origin popups, preventing Spectre-class side-channel attacks.
Cross-Origin-Resource-Policy (CORP): same-origin prevents other sites from loading your resources, protecting against cross-origin data leaks.
Common Misconfigurations
Setting HSTS with a short max-age in production: A max-age of 300 seconds provides almost no protection. Use 31536000 (one year) after testing.
Using CSP with unsafe-inline and unsafe-eval: This effectively disables CSP's XSS protection. Migrate to nonce-based CSP.
Setting X-Frame-Options: ALLOW-FROM: This value has been removed from browser implementations. Use CSP frame-ancestors instead.
Forgetting the 'always' directive in Nginx: Without always, Nginx only adds headers on successful (2xx/3xx) responses. Error pages (4xx/5xx) will lack security headers, which is exactly when you need them most.
Not setting headers on all response types: Security headers must be set on HTML responses, API responses, and error pages. A missing header on a single endpoint can be exploited.
Complete Server Configuration
Nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none';" always;
Apache (.htaccess):
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none';"
Testing Your Headers
Use curl -I https://yourdomain.com to inspect response headers from the command line. Online tools like securityheaders.com grade your configuration from A+ to F. Check headers on multiple paths including your homepage, API endpoints, and error pages. Verify headers after every deployment — configuration changes and reverse proxy updates can silently remove headers.