Security

HTTP Security Headers — Best Practices + Examples

meine-ip.info Editorial · · 6 min read · Updated May 2026
HTTP Header HSTS CSP X-Frame-Options Security Header Webmaster Security
NordVPN
Recommended
Ad
  • 5,000+ Servers
  • No Logging
  • Up to 10 Devices
Protect your IP with NordVPN →

Misconfigured or missing HTTP headers are the most common gap in modern web setups — and at the same time the easiest to close. This guide covers the six most important security headers, how they work, with ready-to-use nginx and Apache examples plus an audit checklist at the end.

Quick answer

Set these headers on every public web server:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=()

Verify the result with our HTTP Header Check — the score should be at least B. For A, finer CSP directives are needed.

The six most important headers in detail

1. Strict-Transport-Security (HSTS)

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

Tells the browser: for the next 365 days always HTTPS, never HTTP. Prevents SSL-stripping attacks on open Wi-Fi.

  • max-age in seconds, recommendation: 31536000 (1 year).
  • includeSubDomains — also applies to mail.example.com, api.example.com etc.
  • preload — prerequisite for the Chrome HSTS Preload List. Browsers then serve your site HTTPS-only from the start, before the first request.

More background: HSTS in the glossary.

2. Content-Security-Policy (CSP)

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'

The most powerful security header — and the trickiest. Defines which domains the browser may load scripts, styles, images, fonts & co. from. Protection against XSS and code injection.

Understanding directives:

Directive Controls
default-src Fallback for all unset directives
script-src JavaScript sources
style-src CSS sources
img-src Image sources
connect-src XHR, WebSocket, fetch() targets
font-src Web font sources
frame-ancestors Who may embed this page?

Practical recommendation: start with Content-Security-Policy-Report-Only (same format, but only reports, doesn't block). Watch the reports for two weeks to see what would be blocked — then switch to enforced.

3. X-Frame-Options

X-Frame-Options: SAMEORIGIN

Prevents clickjacking: your page cannot be loaded in an <iframe> of a foreign domain. Values:

  • DENY — no framing at all.
  • SAMEORIGIN — only same origin may frame (standard for most sites).
  • ALLOW-FROM uri — a specific origin (deprecated, replaced by CSP frame-ancestors).

CSP frame-ancestors is the modern variant and overrides X-Frame-Options in new browsers — but setting X-Frame-Options as a backup doesn't hurt.

4. X-Content-Type-Options

X-Content-Type-Options: nosniff

Prevents MIME sniffing: the browser only accepts the Content-Type reported by the server and doesn't "guess" an alternative. Protects against tricks like JS disguised as an image that the browser executes once it detects JS code in the "image".

Only one valid value: nosniff. Should be set on every server, always.

5. Referrer-Policy

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

Controls what referrer info is sent when users click external links. Privacy-relevant — the default browser value reveals the full URL including query parameters to the target site on every outbound link.

Recommended values:

Value Behaviour
no-referrer send nothing — maximum privacy
strict-origin-when-cross-origin only origin (domain) for cross-origin, full URL for same-origin — good default
same-origin full URL for same-origin, nothing for cross-origin

6. Permissions-Policy

Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=()

Successor to Feature-Policy. Explicitly disables browser APIs (camera, microphone, geolocation, Payment Request &amp; co.) for your site when they are not needed. Reduces attack surface: even if XSS lands, the injected code can't access the camera.

Empty () means: off completely. (self) means: own domain only. (self "https://trusted.com") means: own + one external.

Example configuration: nginx

server {
    listen 443 ssl http2;
    server_name example.com;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:" always;
    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 Permissions-Policy "geolocation=(), camera=(), microphone=()" always;

    # ... rest of your config
}

The always flag is important — without it, headers are not sent on 4xx/5xx responses.

Example configuration: Apache

In .htaccess or vhost config (mod_headers must be active):

<IfModule mod_headers.c>
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:"
    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 Permissions-Policy "geolocation=(), camera=(), microphone=()"
</IfModule>

Audit checklist

Before and after every deploy:

  1. ☐ HSTS set with max-age ≥ 1 year
  2. ☐ CSP set (not just Report-Only)
  3. ☐ X-Content-Type-Options: nosniff
  4. ☐ X-Frame-Options OR CSP frame-ancestors
  5. ☐ Referrer-Policy at least strict-origin-when-cross-origin
  6. ☐ Permissions-Policy empty for unused APIs
  7. ☐ No Server header with version number (information disclosure)
  8. ☐ No X-Powered-By: PHP/8.x (same reason)
  9. ☐ Verify with HTTP Header Check against the live URL
  10. ☐ Ideally: score A reached

Common pitfalls

Allow inline scripts in CSP? 'unsafe-inline' opens the XSS door. Better solution: use nonces or hashes — example script-src 'self' 'nonce-r4nd0m'. Every allowed <script> tag gets the same nonce attribute, generated per request.

X-XSS-Protection: 0 or omit? The old header is deprecated. Modern browsers ignore it. If you set it, use X-XSS-Protection: 0 — anything else can actually open new vulnerabilities.

HSTS on a subdomain I haven't deployed everywhere? Beware of includeSubDomains — if legacy.example.com still runs HTTP, you lock yourself out. Clean up first, then enable HSTS.

Preload list — can it be removed? Theoretically yes (removal request), practically it takes weeks to months until all browser versions forget the entry. Don't add without a plan.

Frequently asked questions

Does CSP hurt performance? Not noticeably. The headers are a few hundred bytes per response. What costs is maintenance — on complex sites with many third-party scripts, CSP needs regular adjustments.

Is it enough to set headers only on HTTPS? HSTS can only work over HTTPS. The rest is usable over HTTP too, but if anyone uses HTTP, that's not a secure setup anyway. Generally: ditch HTTP entirely and redirect port 80 only to HTTPS via 301.

What if Cloudflare or another CDN sits in front? Cloudflare can add many headers automatically — check their "Security Headers" page rule. With DIY-CDN setup (e.g. your own nginx as reverse proxy): set headers in the reverse proxy, not the backend, since the browser sees them from the edge server.

How often should I re-check? At least after every major deploy. Ideally automated daily — e.g. UptimeRobot heartbeat monitoring combined with a cron that runs against the HTTP Header Check and alerts on score drops.

Related tools at a glance

Surfshark
Best Value
Ad
  • Unlimited Devices
  • CleanWeb
  • From €1.99/month
Try Surfshark VPN →