The Complete Guide to HTTP Security Headers
Master the essential HTTP security headers including Content-Security-Policy, HSTS, X-Frame-Options, and more. Learn implementation strategies with practical examples.

HTTP security headers are your first line of defense against common web attacks. These headers instruct browsers on how to handle your content, preventing cross-site scripting (XSS), clickjacking, and other vulnerabilities.
Content-Security-Policy (CSP)
CSP is arguably the most powerful security header. It controls which resources the browser is allowed to load, effectively preventing XSS attacks by blocking unauthorized scripts.
Basic CSP Structure
A CSP consists of directives that control different resource types:
- default-src: Fallback for other directives
- script-src: JavaScript sources
- style-src: CSS sources
- img-src: Image sources
- connect-src: AJAX, WebSocket, fetch sources
- frame-ancestors: Who can embed this page
Example Implementation
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://trusted-cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.example.com
CSP Best Practices
- Start with report-only mode to identify issues
- Avoid 'unsafe-inline' when possible—use nonces or hashes
- Never use 'unsafe-eval'
- Be specific with allowed domains
- Use report-uri to collect violation reports
Strict-Transport-Security (HSTS)
HSTS tells browsers to only access your site over HTTPS, preventing protocol downgrade attacks and cookie hijacking.
HSTS Directives
- max-age: How long (in seconds) to remember the HTTPS-only rule
- includeSubDomains: Apply to all subdomains
- preload: Request inclusion in browser preload lists
Recommended Configuration
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Warning: Start with a short max-age (e.g., 300 seconds) and gradually increase it. HSTS errors can make your site inaccessible until the max-age expires.
X-Frame-Options and frame-ancestors
These headers prevent clickjacking attacks by controlling whether your page can be embedded in frames.
X-Frame-Options (Legacy)
- DENY: Never allow framing
- SAMEORIGIN: Only allow framing from same origin
- ALLOW-FROM uri: Allow specific origin (limited browser support)
CSP frame-ancestors (Modern)
The CSP frame-ancestors directive is more flexible and should be preferred:
Content-Security-Policy: frame-ancestors 'self' https://trusted-partner.com
Recommendation: Use both headers for maximum compatibility:
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
X-Content-Type-Options
This header prevents MIME type sniffing, which can turn non-executable files into executable content.
X-Content-Type-Options: nosniff
Always set this header. There's no reason not to—it has no drawbacks and prevents MIME confusion attacks.
Referrer-Policy
Controls how much referrer information is included when navigating away from your site.
Common Policies
- no-referrer: Never send referrer
- same-origin: Send referrer only for same-origin requests
- strict-origin: Send origin only, and only over HTTPS
- strict-origin-when-cross-origin: Full URL for same-origin, origin only for cross-origin (recommended)
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy (formerly Feature-Policy)
Controls which browser features can be used on your page:
Permissions-Policy: camera=(), microphone=(), geolocation=(self), payment=(self)
This prevents embedded content from accessing sensitive features without your explicit permission.
Implementation Examples
Nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self';" always;
Apache
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self';"
Next.js / Vercel
// next.config.js
const securityHeaders = [
{ key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' },
{ key: 'X-Frame-Options', value: 'SAMEORIGIN' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
];
module.exports = {
async headers() {
return [{ source: '/:path*', headers: securityHeaders }];
},
};
Testing Your Headers
After implementing security headers, test your configuration:
- Use SecScanner to automatically audit all security headers
- Check browser developer tools Network tab for header values
- Use CSP report-only mode initially to catch issues
- Test in multiple browsers for compatibility
Security headers are essential for modern web applications. Start with the basics and progressively tighten your policy as you identify and address compatibility issues.
Related Articles
Check Your Website Security
Want to see how your website measures up? Run a free security scan with SecScanner to identify vulnerabilities and get actionable remediation guidance.
Scan Your Website Free