HTTP Security Headers: The Complete Implementation Guide
HTTP security headers are response headers that instruct browsers on how to handle your site's content. They are one of the most cost-effective security improvements you can make — a few lines of server configuration that mitigate entire classes of attacks like XSS, clickjacking, and protocol downgrade attacks. This guide covers every major security header with real configuration examples.
1. Strict-Transport-Security (HSTS)
HSTS tells browsers to always use HTTPS for your domain — even if the user types http://. This prevents SSL-stripping attacks, where an attacker downgrades your HTTPS connection to HTTP.
# Minimal (start here for testing) Strict-Transport-Security: max-age=300 # Production recommended Strict-Transport-Security: max-age=31536000; includeSubDomains # Maximum security (HSTS preload — irreversible without removal process) Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
includeSubDomains
Applies HSTS to all subdomains. Only add if ALL subdomains support HTTPS.
preload
Hardcodes your domain into browsers. Requires hstspreload.org submission. Very hard to undo.
2. Content-Security-Policy (CSP)
CSP is the most powerful security header, but also the most complex. It defines which sources are allowed to load scripts, styles, images, fonts, and other resources. A strict CSP prevents most XSS attacks — even if an attacker injects malicious code, the browser refuses to execute it if it violates the policy.
# Restrictive policy (start here, then loosen as needed) Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.trusted.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://api.yourdomain.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; # Report-only mode (test without breaking things) Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint
Start with Content-Security-Policy-Report-Only to identify violations without breaking your site. Use a service like Report URI to collect and analyse violation reports.
3. X-Frame-Options
Prevents your site from being embedded in <iframe>, <frame>, or <object> elements on other sites. This stops clickjacking attacks where an attacker overlays your site invisibly to trick users into clicking on hidden elements.
X-Frame-Options: DENY # Never allow framing X-Frame-Options: SAMEORIGIN # Allow framing only by same origin
Note: CSP's frame-ancestors directive is the modern replacement and provides more granular control. Set both for maximum compatibility.
4. X-Content-Type-Options
Prevents browsers from MIME-sniffing the content type of responses. Without this header, a browser might interpret a text file as JavaScript if it looks like script code — a vector for content injection attacks.
X-Content-Type-Options: nosniff
This is a zero-risk header — add it to every site unconditionally.
5. Referrer-Policy
Controls how much referrer information is sent when navigating from your site to external URLs. Without a policy, browsers may leak the full URL (including query parameters with tokens or search terms) in the Referer header.
# Recommended: send origin only for cross-origin requests Referrer-Policy: strict-origin-when-cross-origin # Maximum privacy: never send referrer information Referrer-Policy: no-referrer
6. Permissions-Policy
Controls which browser features and APIs your site can use — and prevents third-party iframes from accessing them. Replaces the older Feature-Policy header.
# Disable unnecessary browser APIs Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=(), payment=(self)
Complete Server Configuration Examples
# Nginx — complete security headers block
# In your server {} block:
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 Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; frame-ancestors 'self'; base-uri 'self';" always;# Next.js — next.config.js security headers
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' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
];
module.exports = {
async headers() {
return [{ source: '/(.*)', headers: securityHeaders }];
},
};Security Header Grading Reference
| Header | Priority | Risk if Missing |
|---|---|---|
| Strict-Transport-Security | Critical | SSL stripping, protocol downgrade attacks |
| Content-Security-Policy | Critical | XSS, data injection attacks |
| X-Frame-Options | High | Clickjacking attacks |
| X-Content-Type-Options | High | MIME sniffing, drive-by downloads |
| Referrer-Policy | Medium | Information leakage to third parties |
| Permissions-Policy | Medium | Unauthorised API access from third-party frames |
Test your security headers instantly
Our Security Headers checker scans any URL and gives you a grade, missing headers, and specific fix recommendations — in under 3 seconds.
Scan your security headers →