HTTP Security Headers Explained: The Complete Guide

HTTP security headers are response headers your server sends that instruct the browser to behave more defensively. They decide which scripts a page may run, whether other sites can frame it, whether the connection must use HTTPS, and how much referrer data leaks. They are among the cheapest security wins available, since most are a single line of server configuration.

None of them encrypt anything; that job belongs to the TLS certificate. Instead, headers harden the browser side of the connection against common web attacks. You can see exactly which headers any site sends, and how it scores, with our security headers tool.

The headers that matter

Header Defends against Guide
Content-Security-Policy Cross-site scripting (XSS), injection CSP explained
Strict-Transport-Security Protocol downgrade, SSL stripping HSTS explained
X-Frame-Options Clickjacking X-Frame-Options
X-Content-Type-Options MIME sniffing X-Content-Type-Options
Referrer-Policy Referrer data leakage Referrer-Policy
Permissions-Policy Unwanted access to camera, mic, geolocation Permissions-Policy

Content-Security-Policy

CSP is the most powerful header and the hardest to get right. It whitelists the sources a page may load scripts, styles, and other resources from, which neutralises most cross-site scripting. Worth the effort for any serious site. See CSP explained.

Strict-Transport-Security (HSTS)

HSTS forces browsers to use HTTPS for your domain, closing the window where a first plain-HTTP request can be intercepted and downgraded. See HSTS explained.

The supporting cast

X-Content-Type-Options: nosniff stops the browser from second-guessing content types (guide). X-Frame-Options (or CSP frame-ancestors) blocks clickjacking (guide). Referrer-Policy controls how much URL data is sent to other sites (guide). Permissions-Policy restricts powerful browser features like camera and geolocation (guide).

Do not overlook how cookies are set either: the HttpOnly, Secure, and SameSite attributes are a security control of their own, covered in cookie security attributes.

The cross-origin isolation trio

Three newer headers work as a set rather than individually: Cross-Origin-Opener-Policy (COOP), Cross-Origin-Embedder-Policy (COEP), and Cross-Origin-Resource-Policy (CORP). COOP severs the window.opener relationship between your page and anything that opened it, COEP requires every subresource to explicitly opt in to being embedded, and CORP lets a resource declare who may load it.

Send Cross-Origin-Opener-Policy: same-origin together with Cross-Origin-Embedder-Policy: require-corp and the browser marks your page as cross-origin isolated. That state is what unlocks SharedArrayBuffer and high-resolution timers, both of which browsers restricted after Spectre. If you do not need those APIs, COOP alone is still a worthwhile hardening step against cross-window attacks, and it is far easier to deploy than COEP, which breaks any third-party resource that does not serve CORP headers.

What security headers cannot do

Headers are instructions to a browser. That single fact explains most of their limits, and it is worth being blunt about them, because a good header grade is easy to mistake for a secure application.

  • They do not protect non-browser clients. An attacker using curl, a script, or a proxy simply ignores every header you send. Headers reduce what a victim's browser can be tricked into doing; they do nothing to harden your API against direct abuse.
  • They are not a substitute for fixing the bug. CSP is mitigation for cross-site scripting, not a fix. If user input reaches your HTML unescaped, the vulnerability is still there and a single CSP misconfiguration re-exposes it.
  • They do not encrypt anything. Encryption is the TLS layer's job. HSTS only tells the browser to use that layer.
  • They do not validate your certificate. A site can score well on headers while serving an expired certificate. Those are separate checks, which is why our full report runs both.
  • A perfect grade is not a security audit. Scoring tools measure which headers are present, not whether your CSP is actually restrictive. A policy of default-src * is a valid CSP and a useless one.

Headers you can safely remove

Several headers that appear in older hardening guides are now obsolete, and a few actively cause harm. Removing them is as much a part of the job as adding the current set.

Header Status What to do
X-XSS-Protection Obsolete. The Chrome XSS Auditor it controlled was removed in 2019, and the filter itself introduced vulnerabilities Remove it, or send 0
Public-Key-Pins (HPKP) Dead. Removed from Chrome; a mistake could lock users out of your domain for the pin's lifetime Remove it
Expect-CT Obsolete. Certificate Transparency is now enforced by default for publicly trusted certificates Remove it
Feature-Policy Renamed Replace with Permissions-Policy, which has different syntax

If a checker still rewards X-XSS-Protection, treat that as a sign the checker is out of date rather than a reason to add the header back.

Setting headers on your server

Every header here is a line of configuration. The awkward part is usually knowing where to put it, because a header set in your application can be overwritten, duplicated, or stripped by a proxy or CDN in front of it.

On nginx:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" 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;

On Apache:

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"

Two traps catch people repeatedly. First, nginx's add_header is not inherited into a location block that declares its own add_header directives: the moment a block adds one header, it stops inheriting every header from the parent scope, so you have to re-declare them all inside that block. Second, a CDN or reverse proxy can add its own copy of a header, and duplicated or conflicting values behave unpredictably. Always verify against the live response rather than trusting the config file.

How to check and score a site

You do not need to read raw headers by hand. Our security headers tool fetches a site's response headers and grades them with specific recommendations. For the manual methods (browser dev tools and curl), see how to check security headers.

A sensible order of adoption: add the easy, low-risk headers first (X-Content-Type-Options, X-Frame-Options, Referrer-Policy), turn on HSTS once you are confident HTTPS is solid, then take your time building a correct Content-Security-Policy in report-only mode before enforcing it.

That order is deliberate, because the risk profile of these headers is wildly uneven:

  1. Deploy immediately. X-Content-Type-Options: nosniff, X-Frame-Options, and Referrer-Policy are effectively free. The only site that breaks under X-Frame-Options is one that is genuinely framed somewhere it needs to be, which you will know about.
  2. Deploy carefully. HSTS is safe but hard to reverse. Once a browser has seen your max-age, it will refuse plain HTTP for your domain for that entire period, so start with a short max-age (say 300 seconds), confirm nothing breaks, and only then raise it to a year. Add includeSubDomains only after checking that every subdomain, including internal ones, serves valid HTTPS. Preloading via hstspreload.org requires max-age of at least 31536000 plus includeSubDomains and preload, and removal from the preload list takes months.
  3. Deploy slowly. CSP is the one that breaks sites. Ship it as Content-Security-Policy-Report-Only first, collect violation reports from real traffic for a couple of weeks, fix what they surface, and only then switch to the enforcing header. Both can be sent at once, which lets you enforce a loose policy while testing a stricter one.

The pattern worth internalising is that the headers protecting you most are the ones most likely to break something. That is not a reason to skip them, just a reason to stage them.

Headers are a rare security measure that is both cheap and high impact. Audit any site with our security headers tool, or have an agent pull them through the security_headers tool in our MCP server.

Frequently asked questions

What are HTTP security headers?

HTTP security headers are response headers a web server sends that tell the browser how to behave more safely: which scripts to trust, whether to allow framing, whether to force HTTPS, and more. They are a cheap, high-impact layer of defense against attacks like cross-site scripting and clickjacking.

Which security headers are most important?

Content-Security-Policy and Strict-Transport-Security give the most protection, followed by X-Content-Type-Options, X-Frame-Options (or CSP frame-ancestors), Referrer-Policy, and Permissions-Policy.

How do I add security headers?

You set them in your web server, application, or CDN configuration as HTTP response headers. Start in a report-only or permissive mode for the strict ones like CSP, then tighten.

Do security headers slow down my site?

No measurably. Each header adds a few dozen bytes to every response, which is negligible. Content-Security-Policy can add work if you use nonces, since the nonce must be generated per request and prevents full-page caching of the HTML, but the header itself costs nothing. HSTS actually saves a round trip by removing the HTTP-to-HTTPS redirect for repeat visitors.

Which security headers are obsolete?

X-XSS-Protection, Public-Key-Pins (HPKP), and Expect-CT are all obsolete and should be removed rather than configured. Feature-Policy has been renamed to Permissions-Policy with different syntax. Older hardening guides still recommend these, and some scanners still reward them, but browsers have dropped support and HPKP in particular can lock users out of your domain.

Is it safe to turn on HSTS?

Yes, provided HTTPS works reliably on every hostname it covers, but it is hard to undo. Once a browser has seen your max-age it will refuse plain HTTP for your domain until that timer expires. Start with a short max-age such as 300 seconds, verify nothing breaks, then raise it. Add includeSubDomains only after confirming every subdomain serves valid HTTPS.

Do security headers protect my API?

Barely. Security headers are instructions to a browser, so an attacker calling your API directly with curl or a script ignores them entirely. They reduce what a victim's browser can be tricked into doing. Protecting an API needs authentication, authorization, input validation, and rate limiting instead.