Security9 min readFebruary 10, 2024

HTTP Security Headers: The Complete Implementation Guide

HTTP security headers are one of the most underutilized defenses in web security. This guide covers every critical header, what it does, and exactly how to implement it.

AdvertisementAd Slot — Article Header (728×90)

Why HTTP Security Headers Matter

HTTP security headers are instructions your server sends to browsers, telling them how to handle your content securely. They're your defense against some of the most common web attacks: XSS, clickjacking, MIME sniffing, and protocol downgrade attacks.

The best part? They're free, easy to implement, and require no code changes to your application — just web server configuration.

A website without security headers is like a bank with an unlocked door: it might never be robbed, but you've given attackers every opportunity.

The Critical Security Headers (Don't Skip These)

1. Strict-Transport-Security (HSTS)

Tells browsers to always connect over HTTPS, even if the user types http://.

\u0060\u0060\u0060 Strict-Transport-Security: max-age=31536000; includeSubDomains; preload \u0060\u0060\u0060

Parameters:

  • \u0060max-age=31536000\u0060 — Remember this for 1 year (in seconds)
  • \u0060includeSubDomains\u0060 — Apply to all subdomains
  • \u0060preload\u0060 — Eligible for browser preload lists

Implementation in Nginx: \u0060\u0060\u0060nginx add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; \u0060\u0060\u0060

⚠ Warning: Start with a short max-age (300 seconds) until you're certain your entire site works over HTTPS. Once browsers cache HSTS, HTTP access is blocked for the duration.

2. Content-Security-Policy (CSP)

Specifies which sources are trusted for scripts, styles, images, and other resources. Prevents XSS by blocking unauthorized scripts.

Strict CSP example: \u0060\u0060\u0060 Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; \u0060\u0060\u0060

For Google Analytics: \u0060\u0060\u0060 script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com; connect-src 'self' https://www.google-analytics.com; \u0060\u0060\u0060

Start in report-only mode to identify violations before blocking: \u0060\u0060\u0060 Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report \u0060\u0060\u0060

3. X-Frame-Options

Prevents your site from being embedded in iframes, blocking clickjacking attacks.

\u0060\u0060\u0060 X-Frame-Options: DENY \u0060\u0060\u0060

Options:

  • \u0060DENY\u0060 — No framing allowed anywhere
  • \u0060SAMEORIGIN\u0060 — Framing allowed by same origin only
  • \u0060ALLOW-FROM uri\u0060 — Deprecated, use CSP frame-ancestors instead

Note: CSP's \u0060frame-ancestors\u0060 directive supersedes this header in modern browsers. Implement both for maximum compatibility.

4. X-Content-Type-Options

Stops browsers from "sniffing" the content type of responses, preventing MIME confusion attacks.

\u0060\u0060\u0060 X-Content-Type-Options: nosniff \u0060\u0060\u0060

Without this, a server returning a text file containing JavaScript could have that file executed as a script by the browser.

5. Referrer-Policy

Controls how much referrer information is sent with requests.

\u0060\u0060\u0060 Referrer-Policy: strict-origin-when-cross-origin \u0060\u0060\u0060

Options from most to least privacy:

  • \u0060no-referrer\u0060 — Never send referrer
  • \u0060strict-origin\u0060 — Send only origin (no path) for cross-origin
  • \u0060strict-origin-when-cross-origin\u0060 — Full URL same-origin, origin-only cross-origin (recommended)
  • \u0060no-referrer-when-downgrade\u0060 — Don't send when going HTTPS → HTTP
  • \u0060unsafe-url\u0060 — Always send full URL (bad for privacy)

6. Permissions-Policy (formerly Feature-Policy)

Controls which browser APIs and features can be used.

\u0060\u0060\u0060 Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() \u0060\u0060\u0060

The \u0060interest-cohort=()\u0060 directive opts out of Google's FLoC (now deprecated but still good practice).

Important But Optional Headers

Cross-Origin-Opener-Policy (COOP)

Isolates your page in its own browsing context group, preventing cross-origin windows from accessing your window object.

\u0060\u0060\u0060 Cross-Origin-Opener-Policy: same-origin \u0060\u0060\u0060

Required if you want \u0060SharedArrayBuffer\u0060 access (for WebAssembly threads).

Cross-Origin-Embedder-Policy (COEP)

Prevents resources that don't explicitly grant permission from being embedded.

\u0060\u0060\u0060 Cross-Origin-Embedder-Policy: require-corp \u0060\u0060\u0060

Cross-Origin-Resource-Policy (CORP)

Controls which origins can load your resources.

\u0060\u0060\u0060 Cross-Origin-Resource-Policy: same-origin \u0060\u0060\u0060

Headers That Reveal Too Much

Some headers are dangerous because they expose server information that helps attackers:

X-Powered-By

Remove this immediately. It reveals your backend technology (PHP, Express.js, ASP.NET) and version, helping attackers find known vulnerabilities.

\u0060\u0060\u0060nginx # Nginx: headers already not sent # Apache: Header unset X-Powered-By

# Express.js: app.disable('x-powered-by'); \u0060\u0060\u0060

Server

The Server header reveals your web server software and version. Minimize what you expose.

\u0060\u0060\u0060nginx server_tokens off; # Hides nginx version \u0060\u0060\u0060

X-AspNet-Version / X-AspNetMvc-Version

Remove these in ASP.NET applications: \u0060\u0060\u0060xml \u0060\u0060\u0060

Performance Headers

These aren't security headers but they significantly impact user experience:

Cache-Control

Controls how browsers and CDNs cache responses.

\u0060\u0060\u0060 # For static assets (versioned with hash in filename): Cache-Control: public, max-age=31536000, immutable

# For HTML pages: Cache-Control: no-cache, no-store, must-revalidate

# For API responses: Cache-Control: private, max-age=0, must-revalidate \u0060\u0060\u0060

Content-Encoding

Enables compression. Make sure gzip or brotli is enabled:

\u0060\u0060\u0060nginx gzip on; gzip_types text/plain text/css application/json application/javascript; brotli on; # Requires ngx_brotli module \u0060\u0060\u0060

Web Server Implementation

Nginx

\u0060\u0060\u0060nginx server { # Security headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; 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=()" always; add_header Content-Security-Policy "default-src 'self'" always; # Remove info-leaking headers server_tokens off; # Performance gzip on; gzip_vary on; } \u0060\u0060\u0060

Apache

\u0060\u0060\u0060apache Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" Header always set X-Frame-Options "DENY" Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()" Header unset X-Powered-By

ServerTokens Prod ServerSignature Off \u0060\u0060\u0060

Cloudflare (Transform Rules)

If you use Cloudflare, you can add headers via Transform Rules in the dashboard without touching your server config. This is particularly useful for HSTS and X-Frame-Options.

Testing Your Security Headers

After implementing headers, verify them:

  1. Use our HTTP Header Checker to see all headers in real-time
  2. Check securityheaders.com for a letter-grade score
  3. Use browser DevTools → Network → click any request → Headers tab
  4. Test with \u0060curl -I https://yourdomain.com\u0060

Security Headers Score Card

HeaderPriorityImplementation EffortImpact
HSTSCriticalLowHigh
X-Content-Type-OptionsCriticalVery LowMedium
X-Frame-OptionsHighVery LowHigh
Referrer-PolicyHighVery LowMedium
CSPHighHighVery High
Permissions-PolicyMediumLowMedium
Start with the low-effort headers (HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy) — they take 5 minutes and significantly improve your security posture. Then implement CSP progressively using report-only mode.

AdvertisementAd Slot — Mid Article (300×250)
Try the tools mentioned in this article
HTTP Header CheckerSSL Certificate Checker