HTTP Security Headers: The Complete Implementation Guide for 2025
Most websites are one missing header away from being vulnerable to clickjacking, XSS, or MIME sniffing. Here's every header that matters, what it does, and the exact code to implement it today.
You've got HTTPS working, the site is fast, and the content looks great. But there's a whole security layer most developers never configure: HTTP response headers. These are server-to-browser instructions that close off entire categories of attacks. Getting them right costs nothing. Ignoring them leaves doors open.
Content-Security-Policy (CSP)
CSP is the most powerful security header and the most complex to configure. It tells the browser exactly which sources of content — scripts, styles, images, fonts, iframes — are permitted to load on your page. Everything else is blocked. Even if an attacker injects a malicious script, the browser refuses to execute it if the source isn't approved.
Content-Security-Policy: default-src 'self';
script-src 'self' https:/cdn.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https:/api.example.com;
object-src 'none';
frame-ancestors 'none';
Content-Security-Policy-Report-Only before enforcing. The browser logs violations without blocking anything — invaluable for finding what you've missed before a live breakage.Strict-Transport-Security (HSTS)
Tells browsers to always connect via HTTPS — even if the user types http:/ or clicks an old HTTP link. After the first HTTPS visit, the browser silently upgrades all subsequent requests without making an HTTP round trip at all.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
The preload flag submits your domain for browser HSTS preload lists — meaning protection kicks in on the very first visit, before any headers have been received. Only add this if your entire domain will remain HTTPS permanently; removal takes months.
X-Frame-Options
Prevents your pages being loaded in an <iframe> on another domain — the mechanism behind clickjacking attacks. SAMEORIGIN allows framing only from your own domain. DENY blocks it entirely.
X-Frame-Options: SAMEORIGIN
The modern equivalent is Content-Security-Policy: frame-ancestors 'self' which offers finer control and should be preferred if you're implementing CSP anyway.
X-Content-Type-Options
A single-value header that prevents MIME-sniffing — browsers guessing a resource's content type from its contents rather than its declared type. This stops attacks where a malicious file declared as one type gets executed as another.
X-Content-Type-Options: nosniff
Referrer-Policy
Controls how much URL information is sent in the Referer header when navigating from your site to others. Without this, full URLs including sensitive query parameters can be sent to every third-party site your pages link to.
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy
Controls which browser APIs and features your site and embedded third-party content can access. A compromised third-party script can't access your users' cameras or location if you've blocked those APIs at the header level.
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
🛡️ HTTP Header Checker
Get a complete security header audit and grade for any website in seconds.
How to Add Headers (Quick Reference)
Apache (.htaccess):
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>
Nginx:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Node / Express: Install helmet and call app.use(helmet()). It sets sensible defaults for all of these in one line.