HTTP Security Headers: Protect Your Site in 2025
Complete guide to HTTP security headers. CSP, HSTS, X-Frame-Options to protect your website.
Introduction to HTTP Security Headers
HTTP security headers are your first line of defense against common web attacks. They instruct browsers to enforce security policies that protect users from cross-site scripting (XSS), clickjacking, data injection, and other threats. This guide covers essential security headers every web application should implement.
Content Security Policy (CSP)
CSP is arguably the most powerful security header, preventing XSS and data injection attacks by controlling which resources the browser can load.
Basic CSP
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
CSP Directives
# Control script sources
script-src 'self' https://cdn.example.com
# Control style sources
style-src 'self' 'unsafe-inline'
# Control image sources
img-src 'self' data: https:
# Control font sources
font-src 'self' https://fonts.gstatic.com
# Control frame sources
frame-src 'none'
frame-ancestors 'none'
# Control connections (fetch, WebSocket, etc.)
connect-src 'self' https://api.example.com
# Control form submissions
form-action 'self'
# Fallback for unspecified resources
default-src 'self'
CSP Special Values
'self'- Same origin only'none'- Block all sources'unsafe-inline'- Allow inline scripts/styles (avoid if possible)'unsafe-eval'- Allow eval() (avoid)'nonce-abc123'- Allow specific scripts with matching nonce'sha256-...'- Allow specific inline script by hash
Recommended Production CSP
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{random}';
style-src 'self' 'nonce-{random}';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;
CSP Report-Only Mode
Test CSP without blocking resources:
Content-Security-Policy-Report-Only:
default-src 'self';
report-uri /csp-report-endpoint
Strict-Transport-Security (HSTS)
HSTS forces browsers to use HTTPS for all future requests to your domain.
# Basic HSTS (1 year)
Strict-Transport-Security: max-age=31536000
# Include subdomains
Strict-Transport-Security: max-age=31536000; includeSubDomains
# Preload list (commit to HTTPS forever)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
HSTS Best Practices
- Start with a short max-age (1 day) and increase gradually
- Only add
includeSubDomainsif ALL subdomains support HTTPS - Only use
preloadif you're certain—it's hard to undo - Submit to hstspreload.org for browser preload lists
X-Frame-Options
Prevents your page from being embedded in iframes (clickjacking protection).
# Block all framing
X-Frame-Options: DENY
# Allow same-origin framing only
X-Frame-Options: SAMEORIGIN
# Deprecated: Allow specific origin
X-Frame-Options: ALLOW-FROM https://example.com
Note: Use CSP's frame-ancestors instead—it's more flexible and widely supported.
X-Content-Type-Options
Prevents browsers from MIME-sniffing responses away from the declared content type.
X-Content-Type-Options: nosniff
This prevents attacks where malicious files are disguised as harmless types. Always use it.
Referrer-Policy
Controls how much referrer information is sent with requests.
# Send no referrer at all
Referrer-Policy: no-referrer
# Only send origin (not full URL)
Referrer-Policy: strict-origin
# Send origin only when downgrading (HTTPS to HTTP)
Referrer-Policy: strict-origin-when-cross-origin
# Send full URL to same origin, origin only cross-origin
Referrer-Policy: origin-when-cross-origin
Recommended Value
Referrer-Policy: strict-origin-when-cross-origin
This balances privacy (not leaking full URLs cross-origin) with functionality (analytics still get origin info).
Permissions-Policy (formerly Feature-Policy)
Controls browser features like camera, microphone, and geolocation.
Permissions-Policy:
camera=(),
microphone=(),
geolocation=(self),
payment=(self "https://payment.example.com"),
fullscreen=(self)
Common Directives
camera=()- Disable camera accessmicrophone=()- Disable microphonegeolocation=(self)- Allow only on same originpayment=(self)- Control Payment Request APIusb=()- Disable WebUSBautoplay=(self)- Control video autoplay
X-XSS-Protection
Legacy XSS filter (deprecated but still used for older browsers).
# Disable (recommended for modern browsers with CSP)
X-XSS-Protection: 0
# Enable with blocking
X-XSS-Protection: 1; mode=block
Note: Modern browsers have deprecated this header. Use CSP instead. Setting to 0 is recommended to avoid edge cases where the filter causes issues.
Cache-Control for Security
Prevent caching of sensitive data:
# Sensitive pages (login, account, etc.)
Cache-Control: no-store, no-cache, must-revalidate, private
# Static assets
Cache-Control: public, max-age=31536000, immutable
Cross-Origin Headers
Cross-Origin-Opener-Policy (COOP)
Isolates your browsing context from cross-origin documents:
# Isolate from popups and openers
Cross-Origin-Opener-Policy: same-origin
# Allow popups but isolate
Cross-Origin-Opener-Policy: same-origin-allow-popups
Cross-Origin-Embedder-Policy (COEP)
Requires cross-origin resources to explicitly grant permission:
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy (CORP)
Protect your resources from being loaded cross-origin:
# Only same-origin can load
Cross-Origin-Resource-Policy: same-origin
# Same-site can load
Cross-Origin-Resource-Policy: same-site
# Anyone can load
Cross-Origin-Resource-Policy: cross-origin
Server Configuration Examples
Nginx
server {
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# CSP
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
# Prevent MIME-sniffing
add_header X-Content-Type-Options "nosniff" always;
# Clickjacking protection
add_header X-Frame-Options "DENY" always;
# Referrer policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions policy
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(self)" always;
}
Express.js with Helmet
import helmet from 'helmet';
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'", "https://api.example.com"]
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true
},
referrerPolicy: {
policy: 'strict-origin-when-cross-origin'
}
}));
Next.js
// next.config.js
const securityHeaders = [
{
key: 'Strict-Transport-Security',
value: 'max-age=31536000; includeSubDomains'
},
{
key: 'X-Content-Type-Options',
value: 'nosniff'
},
{
key: 'X-Frame-Options',
value: 'DENY'
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin'
}
];
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: securityHeaders
}
];
}
};
Testing Security Headers
Online Tools
- SecurityHeaders.com - Grades your headers A-F
- Mozilla Observatory - Comprehensive security scan
- CSP Evaluator - Tests your CSP policy
Command Line
# Check headers with curl
curl -I https://example.com
# Check specific header
curl -s -D - https://example.com -o /dev/null | grep -i "strict-transport"
Browser DevTools
- Open DevTools (F12)
- Go to Network tab
- Select main document request
- View Response Headers section
Security Header Checklist
| Header | Purpose | Priority |
|---|---|---|
| Strict-Transport-Security | Force HTTPS | Critical |
| Content-Security-Policy | Prevent XSS | Critical |
| X-Content-Type-Options | Prevent MIME sniffing | High |
| X-Frame-Options | Prevent clickjacking | High |
| Referrer-Policy | Control referrer leakage | Medium |
| Permissions-Policy | Disable unused APIs | Medium |
| Cross-Origin-*-Policy | Isolation | Medium |
Common Mistakes
- Using CSP
'unsafe-inline'everywhere (defeats XSS protection) - Setting HSTS preload without being ready
- Forgetting headers on error pages
- Not testing after CDN/proxy configuration
- Breaking functionality with overly strict CSP
Tools and Resources
For debugging headers and testing your configuration:
- JSON Formatter for validating config files
- Base64 Encoder for CSP hash generation
- Hash Generator for script integrity hashes
Conclusion
Security headers provide defense in depth for your web applications. Start with the essentials (HSTS, CSP, X-Content-Type-Options), then layer on additional protections. Test thoroughly before deploying, and monitor for CSP violations in production.
Key takeaways:
- HSTS and CSP are critical for modern web security
- Start with report-only mode for CSP
- Use helmet.js or similar libraries for easy implementation
- Test headers with online scanners regularly
- Balance security with functionality
For more developer resources, explore our free online tools. For comprehensive security guidance, see MDN Security Headers and OWASP Secure Headers Project.