HTTP Security Headers Guide: Configuring CSP, HSTS, & Permissions-Policy in Nginx
The definitive guide to configuring HTTP security headers in Nginx. Step-by-step implementation of Content-Security-Policy (CSP), Strict-Transport-Security (HSTS), X-Content-Type-Options, and Permissions-Policy.
HTTP security headers are standardized response directives that instruct web browsers on how to handle content rendering, framing permissions, script execution, and transport encryption. When properly configured, security headers provide a powerful, zero-latency layer of defense capable of mitigating Cross-Site Scripting (XSS), Clickjacking, MIME-sniffing, and SSL stripping attacks before they can execute.
Despite their critical protective value, over 65% of commercial websites fail basic security header audits because configuring headers like Content-Security-Policy (CSP) requires careful planning to prevent accidental breakage of legitimate styles, analytics scripts, and third-party integrations.
1. Content-Security-Policy (CSP): Mitigating XSS and Data Injection
Content-Security-Policy (CSP) is the single most potent browser defense against Cross-Site Scripting (XSS). It defines an explicit whitelist of trusted domains from which scripts, styles, images, and fonts may be loaded and executed. Scripts injected by malicious actors via form inputs or URL parameters are rejected by the browser.
# Strict, production-tested Content-Security-Policy header
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https:; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always;
2. HTTP Strict Transport Security (HSTS): Enforcing Permanent HTTPS
Strict-Transport-Security (HSTS) informs the browser that the website must only be accessed over encrypted HTTPS connections. This eliminates the vulnerable window during initial unencrypted HTTP handshakes where man-in-the-middle attackers could execute SSL stripping attacks.
# Enforce HSTS with a 2-year max-age, all subdomains, and preloading
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
3. Frame Protection: Eliminating Clickjacking with X-Frame-Options
Clickjacking occurs when an adversary embeds your authenticated website inside an invisible <iframe> on an attacker-controlled site, tricking users into clicking invisible buttons (such as confirming payments or deleting accounts). Use X-Frame-Options: DENY combined with CSP frame-ancestors 'none' to block iframe embedding entirely.
add_header X-Frame-Options "DENY" always;
4. MIME Sniffing Prevention: X-Content-Type-Options: nosniff
Web browsers historically attempted to detect the content type of downloaded files regardless of the server-declared Content-Type header (MIME sniffing). This allowed attackers who uploaded a malicious script disguised as an image (.jpg) to have it executed as JavaScript. Setting nosniff strictly forces browsers to trust declared MIME types.
add_header X-Content-Type-Options "nosniff" always;
5. Comprehensive Production Nginx Security Headers Block
Combine all recommended security headers into a unified snippet that can be included across all virtual host definitions in your Nginx infrastructure.
# /etc/nginx/snippets/security-headers.conf
add_header X-Frame-Options "DENY" 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=(), payment=()" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https:; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; object-src 'none'; frame-ancestors 'none';" always;
Developer Security Checklist
- ✓ Deploy Strict-Transport-Security (HSTS) with a minimum 1-year max-age and preload flag
- ✓ Configure Content-Security-Policy (CSP) to restrict script-src and object-src
- ✓ Add X-Content-Type-Options: nosniff to prevent MIME-type sniffing
- ✓ Set X-Frame-Options: DENY or frame-ancestors 'none' to block clickjacking
- ✓ Configure Referrer-Policy: strict-origin-when-cross-origin
- ✓ Audit live headers with Site Check to verify zero grade regression
Security Auditor Synthesis & Key Takeaways
When shipping production web applications and vibe-coded projects built on modern stacks (Next.js, Astro, React, Supabase), perimeter security cannot be an afterthought. Over 85% of customer data leaks and database compromises do not stem from sophisticated zero-day exploits, but rather from trivial misconfigurations: orphaned staging endpoints, exposed environment files, overly permissive CORS policies, and disabled Row Level Security (RLS) rules.
Automated perimeter scanning with Site Check proactively catches these signatures across 36 critical attack vectors, equipping engineering teams and vibe-coders with immediate actionable remediation guides before automated scanning botnets discover the exposed endpoints.