A Practical Guide to HTTP Security Headers for Web Developers
Why modern web applications need CSP, HSTS, and X-Content-Type-Options, and how to configure them properly in Next.js and Nginx.
1. Why Defensive Headers Matter
Defensive HTTP response headers instruct the browser on how to handle content safely. They act as an essential second layer of defense. If a stored Cross-Site Scripting (XSS) flaw exists in an application, a strictly configured Content Security Policy can prevent the browser from executing injected JavaScript or exfiltrating session tokens to an unauthorized domain.
2. Content Security Policy (CSP)
CSP is the most powerful and complex header. It restricts where scripts, styles, images, and fonts can be fetched from. A baseline restrictive policy specifies default-src 'self'; and explicitly permits only trusted origins.
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none';3. HTTP Strict Transport Security (HSTS)
HSTS (Strict-Transport-Security: max-age=31536000; includeSubDomains; preload) forces the browser to only connect via HTTPS for the specified duration (usually 1 year). It mitigates man-in-the-middle SSL stripping attacks completely.
4. Defending Against Clickjacking & MIME-Sniffing
X-Frame-Options: DENY (or frame-ancestors 'none' in CSP) prevents malicious websites from rendering your application inside a hidden iframe to trick users into clicking buttons. X-Content-Type-Options: nosniff prevents browsers from guessing MIME types if an attacker uploads a script disguised as an image.
5. Clean Next.js Configuration Example
In Next.js App Router, configure headers globally inside next.config.ts using the headers() function. This ensures all static and dynamic responses carry your defensive posture.
async headers() {
return [
{
source: '/(.*)',
headers: [
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'X-Frame-Options', value: 'SAMEORIGIN' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' }
],
},
];
}