Security Headers: A Developer's Guide to Hardening Your Website
HTTP security headers are your first line of defense against common web attacks. Here's how to implement them correctly and what each one does.
Security headers are HTTP response headers that instruct browsers to enable or disable specific security features. They're one of the most effective and underimplemented security controls on the web. A properly configured set of security headers prevents entire classes of attacks — XSS, clickjacking, MIME sniffing, protocol downgrade attacks — with a few lines of server configuration.
The essential headers
Content-Security-Policy (CSP) — The most powerful and most complex security header. CSP controls which resources (scripts, styles, images, fonts, etc.) can be loaded and executed on your page.
A basic CSP:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'
This restricts all resources to your own domain, with exceptions for inline styles and data URIs for images. It blocks any injected script from a third-party domain — which is the core XSS mitigation.
Strict-Transport-Security (HSTS) — Forces browsers to use HTTPS for all future connections to your domain. Once set, browsers will refuse HTTP connections even if the user types http://.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options — Prevents browsers from MIME-sniffing a response away from the declared content type. This stops attacks where a file disguised as an image is interpreted as a script.
X-Content-Type-Options: nosniff
X-Frame-Options — Controls whether your site can be embedded in iframes. Prevents clickjacking attacks.
X-Frame-Options: DENY
Note: CSP's frame-ancestors directive is the modern replacement, but X-Frame-Options is still supported for backward compatibility.
Referrer-Policy — Controls how much referrer information is included in requests. Privacy-focused configurations reduce data leakage.
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy — Controls which browser features (camera, microphone, geolocation, etc.) your site can use. Reduces the attack surface if your site is compromised.
Permissions-Policy: camera=(), microphone=(), geolocation=()
Implementation approaches
- Web server (Nginx, Apache) — Configuration files
- CDN/edge (Cloudflare, AWS CloudFront) — Edge rules or workers
- Application framework (Express, Django, Rails) — Middleware
- Meta tags — Some headers (CSP) can be set via HTML meta tags, but response headers are preferred
Common pitfalls
- CSP breaks things — A too-restrictive CSP will break third-party scripts (analytics, consent banners, chat widgets). Start with report-only mode to identify what needs whitelisting.
- HSTS preload is permanent — Once you submit to the HSTS preload list, removing your domain is very slow. Make sure HTTPS works perfectly before enabling preload.
- Inline scripts — If your application uses inline JavaScript, you'll need either
unsafe-inline(weakens CSP) or nonce-based CSP (more complex but secure). - Testing — Always test security headers in staging before production. A misconfigured CSP can take down your site's functionality.
Grading your headers
Tools like SecurityHeaders.com and Mozilla Observatory scan your site and grade your header configuration. Aim for an A or A+ rating. These scores are increasingly checked by security teams during vendor reviews — and showing a strong grade on your trust center is a powerful signal.