← Back to blog
Domain & Network

HTTP Security Headers Checklist: The 7 Headers Every Site Should Send

Five of the seven are a single line you can paste today. HSTS needs a short test run first, and Content-Security-Policy is the one that breaks sites — which is why it starts in report-only mode.

By Rajhussain Kanani7 min read

The short answer

Every site should send seven HTTP security headers: Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy and Cross-Origin-Opener-Policy. They are response headers your server adds to every page, telling the browser to refuse behaviour attackers rely on — loading the site over plain HTTP, running injected scripts, framing your pages invisibly, guessing file types. None of them fix a vulnerability in your code, but each one closes off a way of exploiting it. Five of the seven are a single line with a value you can copy; only CSP takes real thought.

The 7 headers, what each one blocks

1

Strict-Transport-Security (HSTS)

Tells the browser to use HTTPS for your domain for a set time, even if someone types or links http://. That blocks SSL-stripping attacks on public Wi-Fi and removes the insecure first request. Recommended: max-age=31536000; includeSubDomains. Test with a short max-age such as 300 first, and only add includeSubDomains once every subdomain serves HTTPS. The preload directive gets your domain built into browsers, but hstspreload.org requires a max-age of at least one year plus includeSubDomains, and removal is slow — add it last, deliberately.

2

Content-Security-Policy (CSP)

Lists where scripts, styles, images, frames and connections may load from, so an injected <script> from an unlisted source simply doesn't run. It is the strongest defence against cross-site scripting and the easiest header to break a site with. Start with Content-Security-Policy-Report-Only, which reports violations in the browser console without blocking anything, add every analytics, font and embed host your pages genuinely use, then rename it to the enforcing header. The configs below ship it in report-only mode with a starter policy — default-src 'self'; object-src 'none'; base-uri 'self' — that suits a site with no third-party or inline scripts and will need widening for most real ones.

3

X-Content-Type-Options

Always nosniff. Stops browsers second-guessing the declared Content-Type, so an uploaded file served as text can't be sniffed and executed as a script. There is no reason not to send it.

4

X-Frame-Options

SAMEORIGIN (or DENY if nothing should frame your pages) stops other sites loading yours inside an invisible iframe and tricking visitors into clicking — clickjacking. CSP's frame-ancestors directive is the modern replacement and wins where both are set; sending both costs nothing and covers older browsers.

5

Referrer-Policy

strict-origin-when-cross-origin sends the full URL with requests to your own origin but only your domain to other sites, and nothing at all when going from HTTPS to HTTP. That keeps tokens, search terms and private paths in your URLs from leaking to third parties. Current browsers already default to this; setting it explicitly guarantees it.

6

Permissions-Policy

Switches off browser features your site doesn't use, such as camera=(), microphone=(), geolocation=(), so injected code or an embedded third party can't request them. The empty parentheses mean "no origin allowed". Note the syntax differs from the older Feature-Policy header it replaced.

7

Cross-Origin-Opener-Policy (COOP)

same-origin puts your page in its own browsing context group, cutting the link between your window and cross-origin windows that open it or that it opens. That blocks tab-nabbing and a class of cross-site leak attacks. If you rely on a sign-in or payment popup from another domain, use same-origin-allow-popups instead, or the popup can't report back.

Headers to remove, not add

  • X-XSS-Protection — the filter it controlled is gone from modern browsers, and OWASP notes it could introduce XSS in otherwise safe sites. Omit it or send 0.
  • Expect-CT and Public-Key-Pins — both obsolete. Remove them.
  • X-Powered-By and detailed Server values — they advertise your stack and version to anyone scanning for known vulnerabilities.

CheckSEO's HTTP Header Checker fetches any URL and grades its security headers — HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy and Permissions-Policy — flagging what's missing, what's weak, and what your server is leaking. No signup.

Grade your security headers

Copy-paste config

Nginx. The always parameter matters: without it, Nginx only adds headers to successful and redirect responses, so your error pages go out unprotected. Watch inheritance too — a location block with any add_header of its own drops every header set at the server level, so repeat them there.

# Inside the server { } block for your HTTPS site
add_header Strict-Transport-Security
  "max-age=31536000; includeSubDomains" always;
# Report-Only first; rename to Content-Security-Policy when clean
add_header Content-Security-Policy-Report-Only
  "default-src 'self'; object-src 'none'; base-uri 'self'" 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
  "camera=(), microphone=(), geolocation=()" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;

Apache. Enable mod_headers (a2enmod headers on Debian and Ubuntu) and use Header always set for the same reason Nginx needs always.

# Virtual host or .htaccess (requires mod_headers)
<IfModule mod_headers.c>
  Header always set Strict-Transport-Security \
    "max-age=31536000; includeSubDomains"
  Header always set Content-Security-Policy-Report-Only \
    "default-src 'self'; object-src 'none'; base-uri 'self'"
  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 \
    "camera=(), microphone=(), geolocation=()"
  Header always set Cross-Origin-Opener-Policy "same-origin"
</IfModule>

Next.js on Vercel. Return the headers from next.config.ts for every path. poweredByHeader: false removes the X-Powered-By: Next.js header Next.js adds by default. Vercel already sends HSTS with a two-year max-age on deployments, but setting it yourself lets you control includeSubDomains and preload. If you need a nonce-based CSP rather than a host allowlist, the Next.js docs generate it per request in proxy.ts — at the cost of rendering those pages dynamically. For a non-Next project on Vercel, the same key/value pairs go in a headers array in vercel.json.

// next.config.ts
import type { NextConfig } from "next";

// Next.js renders inline scripts, so a CSP without nonces must allow
// 'unsafe-inline'. Add your analytics, font and embed hosts; in
// development, script-src also needs 'unsafe-eval'.
const csp = [
  "default-src 'self'",
  "script-src 'self' 'unsafe-inline'",
  "style-src 'self' 'unsafe-inline'",
  "img-src 'self' blob: data:",
  "object-src 'none'",
  "base-uri 'self'",
  "frame-ancestors 'self'",
].join("; ");

const securityHeaders = [
  {
    key: "Strict-Transport-Security",
    value: "max-age=31536000; includeSubDomains",
  },
  { key: "Content-Security-Policy-Report-Only", value: csp },
  { key: "X-Content-Type-Options", value: "nosniff" },
  { key: "X-Frame-Options", value: "SAMEORIGIN" },
  { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
  {
    key: "Permissions-Policy",
    value: "camera=(), microphone=(), geolocation=()",
  },
  { key: "Cross-Origin-Opener-Policy", value: "same-origin" },
];

const config: NextConfig = {
  poweredByHeader: false,
  async headers() {
    return [{ source: "/:path*", headers: securityHeaders }];
  },
};

export default config;

Cloudflare. Turn on HSTS under SSL/TLS → Edge Certificates. For the rest, create a Response Header Transform Rule (Rules → Transform Rules) that applies to all incoming requests and uses Set static for each header and value above. Cloudflare also offers a one-click "Add security headers" Managed Transform, but check what it sends: its documented set includes X-XSS-Protection: 1; mode=block and Expect-CT, both now discouraged, and it adds no CSP, Permissions-Policy or COOP. A custom rule is the better choice.

How to verify they're live

From a terminal, curl -sI https://yourdomain.com prints the response headers. In a browser, open DevTools → Network, reload, click the document request and read Response Headers. Check more than the home page: a 404 URL (to confirm error responses carry them), a subdomain, and the http:// version, which should redirect to HTTPS — the redirect should be a permanent 301. If you just changed a CDN or proxy config, purge its cache first; cached responses keep their old headers.

Do security headers affect SEO?

Not directly. Google uses HTTPS as a lightweight ranking signal, but it doesn't grade response headers. The indirect effects are real, though: HSTS removes the HTTP-to-HTTPS redirect hop for returning visitors, and a compromised site injecting spam links or redirects will lose rankings far faster than any missing header costs it. Treat headers as part of basic site hygiene — the same category as the checks in a website health check.

Check your headers now

CheckSEO's HTTP Header Checker shows every response header a URL returns and grades the security ones, explaining what each missing or weak header leaves exposed — run it before and after you deploy the config above.

Frequently asked questions

What are HTTP security headers?

Response headers a server sends with each page that tell the browser to enforce security rules: use HTTPS only, block injected scripts, refuse to be framed, stop MIME sniffing, and limit referrer data and browser features. They don't fix vulnerabilities in your code, but they block common ways of exploiting them.

Which security headers does every site need?

Seven: Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy and Cross-Origin-Opener-Policy. Five are single lines with standard values. Test HSTS with a short max-age first, and start CSP in report-only mode, because a strict policy can block legitimate scripts.

Is X-XSS-Protection still needed?

No. The browser XSS filters it controlled have been removed from modern browsers, and OWASP warns the header could create XSS issues in otherwise safe sites. Leave it out or send X-XSS-Protection: 0, and rely on a Content-Security-Policy to block injected scripts instead.

How do I check my website's security headers?

Run curl -sI followed by your URL in a terminal, or open browser DevTools, reload with the Network tab open and inspect the page's response headers. Check an error page and a subdomain as well as the home page, or use an online HTTP header checker to grade them.

Do security headers improve SEO rankings?

Not directly. Google uses HTTPS as a lightweight ranking signal but doesn't grade response headers. The benefits are indirect: HSTS removes a redirect hop for returning visitors, and the headers make it harder for attackers to inject the spam links and redirects that do get sites demoted.

Check your own site with the HTTP Header Checker.

Open HTTP Header Checker

More from the blog