HTTP Response Headers: a practical, secure-by-default setup

Well-chosen response headers harden your site against common attacks, reduce data leakage, and signal modern best practices to browsers. This guide covers seven headers you can set today—what they do, recommended values, and copy‑paste snippets for Nginx, Apache, and IIS.

TL;DR
Overview of core HTTP security headers
Seven headers that boost security with minimal effort.

1) Content-Security-Policy

CSP is a powerful, declarative allow‑list that controls which sources a page can load. It reduces the blast radius of cross‑site scripting (XSS), malicious third‑party code, and HTML injection.

Starter policy:

Content-Security-Policy:
  default-src 'self';
  script-src 'self';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data:;
  font-src 'self' data:;
  connect-src 'self';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'none';

Notes: Avoid “smart quotes” in policies; use plain ASCII quotes (') only. Replace any curly quotes pasted from rich text; otherwise browsers will reject the policy. Prefer nonces or hashes for inline scripts instead of 'unsafe-inline' when possible. Use report-to/report-uri for telemetry during rollout.

Diagram of the Content-Security-Policy request and response flow
How the browser enforces CSP.

2) Permissions-Policy

Formerly Feature‑Policy, this header lets you disable or scope access to device features and powerful APIs (camera, mic, sensors, geolocation, etc.). Ship a deny‑by‑default posture, enabling features per page when needed.

Permissions-Policy:
  camera=(), microphone=(), geolocation=(), gyroscope=(), magnetometer=(),
  usb=(), payment=(), fullscreen=(self)

Values are space‑separated allow‑lists in parentheses. () means “no origins allowed,” while (self) restricts to the current origin. For embedded content, you can allow a partner origin explicitly: geolocation=(self "https://maps.example").

3) Referrer-Policy

Referrer headers leak the origin, path, and query of the page making a request. strict-origin-when-cross-origin is a strong default: it sends the full referrer on same‑origin requests, the origin only on HTTPS → HTTPS cross‑origin, and no referrer on downgrades.

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

Alternatives include no-referrer (most private) and same-origin (restrictive but can break analytics links). Avoid unsafe-url in production.

4) Strict-Transport-Security (HSTS)

HSTS tells browsers to only use HTTPS for a period. Once set, a browser will auto‑upgrade http:// links to https:// and refuse insecure connections for that host.

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

Important: Only enable includeSubDomains and preload after every subdomain serves HTTPS. Preloading submits your domain to a browser‑shipped list and is hard to undo.

5) X-Content-Type-Options

Some browsers attempt to “sniff” content types, which can cause executable content to run from incorrect MIME types. nosniff prevents this behavior for scripts and styles.

X-Content-Type-Options: nosniff

6) X-Frame-Options

Legacy control to prevent clickjacking by blocking framing. Modern CSP uses frame-ancestors, which offers more flexibility. If you need legacy support, set:

X-Frame-Options: DENY
# or
X-Frame-Options: SAMEORIGIN

Do not set both X-Frame-Options and a conflicting frame-ancestors. If both are present, browsers prefer CSP.

7) Access-Control-Allow-Origin (CORS)

Controls which origins may access your resources via cross‑origin requests (XHR, fetch, fonts). For public, unauthenticated assets, you may use *. For any resource that sends or receives credentials (cookies, Authorization), use an explicit origin and echo it selectively.

Access-Control-Allow-Origin: https://example.com
Vary: Origin

When supporting credentials, add Access-Control-Allow-Credentials: true and ensure the value of ACAO is a specific origin (not *).

Implementation snippets

Nginx

add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
# CORS for a specific origin
add_header Access-Control-Allow-Origin "https://example.com" always;
add_header Vary "Origin" always;

Apache (httpd.conf or .htaccess)

Header always set Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Access-Control-Allow-Origin "https://example.com"
Header always set Vary "Origin"

IIS (web.config)

<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Content-Security-Policy" value="default-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'" />
        <add name="Permissions-Policy" value="camera=(), microphone=(), geolocation=()" />
        <add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
        <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains; preload" />
        <add name="X-Content-Type-Options" value="nosniff" />
        <add name="X-Frame-Options" value="DENY" />
        <add name="Access-Control-Allow-Origin" value="https://example.com" />
        <add name="Vary" value="Origin" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

Tip for IIS & CSP: Ensure all quotes are straight ASCII quotes (' or "). Curly quotes copied from Word or a CMS will break the policy.

Matrix of headers, purposes, and recommended values
Recommended defaults to ship today.

Troubleshooting & rollout

Copy‑paste snippets by route

You may want stricter policies on admin routes and looser ones on marketing pages that embed third‑party widgets.

# Example: marketing pages allow specific analytics and video
Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://www.googletagmanager.com https://www.youtube.com;
  img-src 'self' data: https://www.google-analytics.com;
  media-src 'self' https://www.youtube.com;
  style-src 'self' 'unsafe-inline';
  connect-src 'self' https://www.google-analytics.com;
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'none';

Testing checklist

Last updated Aug 17, 2025.