Guides

Security Guide

Security Headers Checklist: What to Configure and Why

Headers are small controls with wide reach. Configure them from an application threat model, test in stages, and avoid policies that protect one route while breaking another.

Security headers tell browsers how to handle content, connections, framing, cross-origin requests, and browser capabilities. They cannot repair an authorization bug or sanitize unsafe HTML, but they can reduce the impact of cross-site scripting, clickjacking, MIME confusion, data leakage, and accidental insecure transport.

Use this checklist as a baseline, not as a copy-and-paste policy. The correct value depends on whether you serve a public website, authenticated application, API, downloads, embedded content, or third-party scripts. Apply headers consistently at the final response boundary, including error responses and redirects where the header semantics require it.

Core headers

Content-Security-Policy

Purpose: limit which scripts, styles, images, frames, connections, and other resources a browser may load. CSP is a defense in depth against XSS and data injection; it does not replace output encoding, input validation, or safe DOM APIs.

Configure: start with a policy that reflects the resources the application actually needs. Prefer nonce- or hash-based script controls for applications that can generate them. Include directives such as object-src 'none', base-uri 'none', and an appropriate frame-ancestors policy. Avoid adding unsafe-inline or unsafe-eval merely to make a broken policy pass.

Roll out: use Content-Security-Policy-Report-Only first, review violations, remove unexpected sources, and then enforce. Test login, payments, analytics, support widgets, uploads, and error pages. A policy that is too broad provides little protection; one that is too narrow can break a critical customer journey.

Strict-Transport-Security

Purpose: tell browsers to use HTTPS for future requests and not bypass certificate errors.

Configure: send HSTS only over HTTPS. Start with a short max-age while confirming that every relevant host supports HTTPS. Add includeSubDomains only when all covered subdomains are ready, including forgotten, internal, and third-party-managed names. Treat preload as a deliberate, difficult-to-reverse commitment, not a default suffix.

Content-Type and X-Content-Type-Options

Purpose: ensure browsers interpret a response as the type the server declares and do not MIME-sniff it into executable content.

Configure: set the correct Content-Type for every response and send X-Content-Type-Options: nosniff. Pay particular attention to user-uploaded files, downloads, JSON, JavaScript, and error pages. This header does not make an unsafe file safe; isolate untrusted uploads and use download-oriented content disposition where appropriate.

Clickjacking protection

Purpose: prevent an attacker from embedding an interactive page and tricking a user into clicking hidden controls.

Configure: use CSP frame-ancestors to define whether a page can be framed. If framing is not required, frame-ancestors 'none' is a strong default. X-Frame-Options: DENY or SAMEORIGIN remains useful for compatibility, but it is less expressive and does not replace a carefully tested CSP policy. APIs that return JSON generally need other controls rather than frame protection.

Headers must match the application

There is no universal security-header string. A payment page, a public API, and an embeddable media widget have different requirements. Use least privilege, then verify that the policy does not disable a required flow.

Privacy and cross-origin controls

Referrer-Policy

Purpose: control how much URL information is sent in the Referer header to another resource.

Configure: strict-origin-when-cross-origin is a reasonable general baseline. Use a stricter policy for sensitive applications or pages whose URLs may contain identifiers. Never put secrets in URLs and do not rely on this header to clean up an unsafe URL design.

Permissions-Policy

Purpose: limit browser features such as camera, microphone, geolocation, payment, and fullscreen.

Configure: disable features the site does not need, and grant required features only to the origins that need them. Test embedded frames and consent flows. Browser support and directive names change, so review the current browser documentation rather than assuming every token has the same effect everywhere.

CORS

Purpose: relax the browser same-origin policy for explicitly approved web origins.

Configure: treat Access-Control-Allow-Origin as an access decision, not a general security header. Use an explicit allowlist for credentialed requests, validate the incoming Origin, configure methods and headers narrowly, and never combine wildcard origins with credentials. CORS does not protect non-browser clients and does not replace API authentication or authorization. Review API protection for the server-side controls that must accompany it.

Cross-origin isolation

Purpose: COOP, COEP, and CORP can separate browsing contexts and restrict how resources are embedded or loaded.

Configure: use them when the application has a clear isolation requirement, such as access to powerful browser capabilities or protection against cross-origin side channels. They can break third-party resources, workers, iframes, and integrations. Deploy on a tested route or origin first and confirm every dependency sends compatible headers.

Headers for sessions and data

The Set-Cookie header is not usually listed with response security headers, but its attributes are essential. Set Secure for HTTPS-only cookies, HttpOnly for cookies that JavaScript does not need, and an appropriate SameSite value. Scope Domain and Path narrowly. Review session expiry, rotation, CSRF protection, and logout behavior together; cookie attributes alone do not secure a session.

Use Cache-Control: no-store for responses containing secrets or user-specific sensitive data. private can prevent shared-cache storage while permitting a browser cache, but it is not equivalent to no-store. Make cache behavior explicit for APIs, authenticated pages, redirects, and error responses.

Remove unnecessary technology disclosure such as X-Powered-By and overly detailed Server values. This is a minor hardening measure, not a substitute for patching or access control. Do not add obsolete headers such as X-XSS-Protection as a modern XSS defense; use CSP and safe coding practices instead.

Test and monitor the policy

Check representative responses with curl -I and a browser developer tools panel. Test success and failure responses, cached and uncached paths, redirects, API preflight requests, file downloads, authenticated pages, and custom error pages. Use automated header tests and a CSP reporting endpoint where appropriate. Treat reports as untrusted input and rate-limit the reporting endpoint.

Deploy in stages:

  1. Record the current headers and application dependencies.
  2. Add low-risk headers such as nosniff and a reviewed referrer policy.
  3. Test HSTS readiness before increasing its duration or scope.
  4. Deploy CSP in report-only mode, fix violations, then enforce on a canary.
  5. Add Permissions-Policy and cross-origin isolation only after testing the needed features.
  6. Monitor browser errors, blocked resources, authentication completion, support tickets, and security reports.

Common mistakes

  • Copying a strict CSP without inventorying scripts, frames, fonts, and connections.
  • Enabling HSTS includeSubDomains before every subdomain has valid HTTPS.
  • Treating a high security score as proof that authorization and input handling are safe.
  • Using wildcard CORS with cookies or reflecting arbitrary origins.
  • Setting headers only on 200 responses and forgetting redirects, errors, or API responses.
  • Caching private content because no-cache was mistaken for no-store.
  • Assuming X-Frame-Options protects an API or replaces frame-ancestors.

Pair this checklist with WAF protection, Bot Management, and Rate Limiting Explained. For a broader architecture review, read How to Hide and Protect Your Origin Server and contact Optimi.

Authoritative references

There are only two hard things in Computer Science: cache invalidation and naming things.

Turn your header list into a safe policy

Talk to our team about security headers, edge controls, and a rollout plan that protects without breaking journeys.

Contact Optimi