Web Security

HTTP Security Headers Checklist: The Complete Guide (2025)

A complete checklist of HTTP security headers every web app should set. Covers CSP, HSTS, X-Frame-Options, CORP, and more — with copy-paste examples for Next.js, nginx, and Express.

January 20, 20265 min readShipSafer Team

HTTP security headers are directives sent by your web server that tell browsers how to behave when handling your site's content. Correctly setting them closes a wide range of attack vectors — XSS, clickjacking, MIME sniffing, cross-origin attacks — with just a few lines of configuration.

This checklist covers every header that matters, what each one does, and how to configure it.

The Critical Headers

1. Content-Security-Policy (CSP)

Prevents: Cross-site scripting (XSS), data injection attacks, clickjacking

CSP is the most powerful security header. It defines which sources the browser is allowed to load scripts, styles, images, fonts, and other resources from.

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' https://api.yourdomain.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'

Key directives:

DirectiveControls
default-srcFallback for all resource types
script-srcJavaScript sources
style-srcCSS sources
img-srcImage sources
connect-srcfetch(), XHR, WebSocket destinations
frame-ancestorsWho can embed this page (replaces X-Frame-Options)
form-actionWhere forms can submit
base-uriAllowed base URL values

Avoid 'unsafe-inline' for scripts. Use nonces or hashes instead.

2. Strict-Transport-Security (HSTS)

Prevents: Protocol downgrade attacks, SSL stripping, man-in-the-middle on HTTP

HSTS tells browsers to only connect to your site over HTTPS, even if the user types http:// or clicks an HTTP link.

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  • max-age=31536000 — Cache for 1 year (minimum for Google preload list)
  • includeSubDomains — Also apply to all subdomains
  • preload — Submit to browser preload lists (hardcodes HTTPS-only in Chrome/Firefox)

Important: Only add preload when you're certain all subdomains serve HTTPS. Removing from the preload list can take months.

3. X-Content-Type-Options

Prevents: MIME type sniffing attacks

X-Content-Type-Options: nosniff

Tells the browser to respect the declared Content-Type and not try to guess what a file is. Without this, a browser might execute a text file as JavaScript if the server sends it with an ambiguous content type.

This is a single value with no configuration — just add it.

4. X-Frame-Options

Prevents: Clickjacking attacks

X-Frame-Options: DENY

Or, if you need to allow embedding within your own domain:

X-Frame-Options: SAMEORIGIN

Note: X-Frame-Options is superseded by CSP's frame-ancestors directive. If you have CSP, use frame-ancestors 'none' or frame-ancestors 'self' there instead. Keep X-Frame-Options for older browser compatibility.

5. Referrer-Policy

Prevents: Leaking sensitive URL paths to third parties

Controls how much referrer information is included with requests when a user navigates away from your site.

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

Policy options:

ValueWhenWhat's sent
no-referrerAlwaysNothing
strict-originCross-originOrigin only
strict-origin-when-cross-originSame-origin: full URL; Cross-origin: origin onlyRecommended
unsafe-urlAlwaysFull URL (dangerous)

Avoid unsafe-url — it leaks session tokens, password reset tokens, and other sensitive URL parameters to third-party analytics and CDNs.

6. Permissions-Policy

Prevents: Unauthorized access to browser APIs (camera, mic, location, etc.)

Formerly Feature-Policy. Restricts which browser features your site can use, and disables features you don't need entirely.

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

Empty parentheses () disable the feature for all origins. Use (self) to allow for your own origin.

7. Cross-Origin-Opener-Policy (COOP)

Prevents: Cross-origin window hijacking, Spectre side-channel attacks

Cross-Origin-Opener-Policy: same-origin

Isolates your browsing context from cross-origin popups, preventing them from accessing your window object and enabling SharedArrayBuffer.

8. Cross-Origin-Resource-Policy (CORP)

Prevents: Cross-origin reads of your resources

Cross-Origin-Resource-Policy: same-origin

Prevents other origins from loading your resources (images, scripts, etc.) using no-CORS requests. Use same-site if you have same-site cross-origin subdomains that need to load your resources.

9. Cross-Origin-Embedder-Policy (COEP)

Required alongside COOP to enable cross-origin isolation (needed for SharedArrayBuffer, high-resolution timers):

Cross-Origin-Embedder-Policy: require-corp

Only enable if all your third-party resources support CORP headers.

Headers to Remove

Some headers leak information about your server and should be removed:

# Remove these:
Server: Apache/2.4.52 (Ubuntu)   # Remove — reveals server software + version
X-Powered-By: Express             # Remove — reveals framework
X-AspNet-Version: 4.0.30319       # Remove — reveals .NET version

Implementation Examples

Next.js (next.config.ts)

const nextConfig = {
  async headers() {
    return [
      {
        source: '/(.*)',
        headers: [
          { key: 'X-Content-Type-Options', value: 'nosniff' },
          { key: 'X-Frame-Options', value: 'DENY' },
          { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
          {
            key: 'Strict-Transport-Security',
            value: 'max-age=31536000; includeSubDomains',
          },
          {
            key: 'Permissions-Policy',
            value: 'camera=(), microphone=(), geolocation=()',
          },
          { key: 'Cross-Origin-Opener-Policy', value: 'same-origin' },
          { key: 'Cross-Origin-Resource-Policy', value: 'same-origin' },
        ],
      },
    ];
  },
};

nginx

add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;

Express (Node.js)

Use the helmet package, which sets most of these automatically:

import helmet from 'helmet';
app.use(helmet());

Priority Order

If you're starting from scratch, implement in this order:

  1. X-Content-Type-Options: nosniff — 30 seconds, zero risk
  2. X-Frame-Options: DENY — 30 seconds, zero risk
  3. Referrer-Policy: strict-origin-when-cross-origin — 30 seconds
  4. Strict-Transport-Security — 5 minutes (test on staging first)
  5. Permissions-Policy — 5 minutes, tailor to your features
  6. Content-Security-Policy — Hours to days (requires auditing all resources)
  7. Cross-Origin-* headers — After CSP is working

CSP is deliberately last because it requires inventorying every resource your page loads and breaks easily if misconfigured. Start with Content-Security-Policy-Report-Only to monitor without enforcement.

http-headers
csp
hsts
security-headers
web-security

Check Your Security Score — Free

See exactly how your domain scores on DMARC, TLS, HTTP headers, and 25+ other automated security checks in under 60 seconds.