siteIQ 5 min read 885 words

Security Headers Explained: What Each One Does and How to Set It

C
Codaiman Admin
Author · Codaiman
September 16, 2026
Updated Sep 22, 2026

Seven HTTP headers stand between your site and a whole category of attacks. Most sites ship none of them. Here's what each one actually prevents, the exact value to set, and the order to add them in without breaking your site.

Security headers are instructions your server sends with every response, telling the browser how to behave. They cost nothing, take an afternoon, and prevent entire categories of attack.

Most websites ship none of them. Partly because the names are opaque, partly because the documentation is written for people who already understand the attacks. Here is the version that assumes you do not.

Strict-Transport-Security (HSTS)

Prevents: an attacker downgrading a visitor from HTTPS to HTTP and reading everything in plain text.

Here is the gap HSTS closes. Someone types yoursite.com — no https://. The browser tries HTTP first. Your server redirects to HTTPS. That very first unencrypted request is interceptable on a shared network, and an attacker who catches it can keep the visitor on HTTP for the whole session.

HSTS tells the browser: for the next year, never use HTTP for this domain, no matter what.

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

One warning: includeSubDomains applies to every subdomain. If an internal tool runs on HTTP at staging.yoursite.com, it will stop loading. Confirm every subdomain is HTTPS before adding that directive, and start with a short max-age like 300 while testing.

Content-Security-Policy (CSP)

Prevents: cross-site scripting (XSS) — the single most common serious web vulnerability.

The attack: someone gets JavaScript onto your page that you did not write, usually through a comment box, a URL parameter or a compromised third-party script. That code runs with full access to your users' session — it can read cookies, submit forms as them, or skim credit card fields at checkout.

CSP is an allowlist of where code may load from. Anything else, the browser refuses to execute.

Content-Security-Policy: default-src 'self'; script-src 'self' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self'

This is the one that breaks sites. Turn on a strict CSP without testing and your analytics, embedded videos and payment widget stop working simultaneously.

The safe rollout, and genuinely the only sensible way to do it:

  1. Ship it as Content-Security-Policy-Report-Only first. The browser logs violations to the console and blocks nothing.
  2. Use the site normally for several days. Click through checkout, submit forms, load every embed.
  3. Add legitimate sources to the allowlist as violations appear.
  4. When the console is quiet under real traffic, rename the header to Content-Security-Policy to enforce it.

Skipping the report-only phase is how people break production on a Friday.

X-Frame-Options

Prevents: clickjacking.

An attacker loads your site in an invisible iframe on their page, overlays it with their own buttons, and the victim clicks what they think is "Play video" while actually clicking "Transfer funds" on your site, already logged in.

X-Frame-Options: DENY

Use SAMEORIGIN if you legitimately embed your own pages. The modern equivalent is CSP's frame-ancestors, but keep this header too — older browsers only understand this one.

X-Content-Type-Options

Prevents: MIME sniffing attacks.

Browsers historically guessed a file's type by looking at its contents rather than trusting the declared type. So a file uploaded as avatar.jpg that actually contains JavaScript could get executed as a script.

X-Content-Type-Options: nosniff

One line, no configuration, no risk of breaking anything. If you add only one header today, add this one.

Referrer-Policy

Prevents: leaking URLs to third parties.

When someone clicks a link off your site, the browser tells the destination which page they came from. If that page was yoursite.com/reset-password?token=abc123, you have just handed a password reset token to an external server — and it lands in their access logs.

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

This sends the full path within your own site and only the bare domain externally. Sensible default for almost everyone.

Permissions-Policy

Prevents: third-party scripts silently accessing camera, microphone or location.

Every embedded script on your page can request these by default. Explicitly deny what you do not use:

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

Empty parentheses mean "nobody". (self) means "only my own site".

The header you should remove

X-Powered-By and a verbose Server header announce your exact stack and version to anyone who looks:

X-Powered-By: PHP/7.4.3

That tells an attacker precisely which published exploits to try. Removing it is not real security — it is not a lock — but there is no reason to hand out a map. In Express: app.disable('x-powered-by'). In Next.js: poweredByHeader: false.

A sensible rollout order

Ordered from zero risk to needs-testing:

  1. X-Content-Type-Options: nosniff — cannot break anything.
  2. Referrer-Policy — cannot break anything.
  3. X-Frame-Options: DENY — safe unless you embed your own pages.
  4. Permissions-Policy — safe once you have confirmed which features you use.
  5. Strict-Transport-Security — safe once every subdomain is HTTPS. Start with a low max-age.
  6. Content-Security-Policy — report-only for a week, then enforce.

Steps 1 to 4 are a fifteen-minute job on any server and cover a surprising amount of ground.

Where to set them

Set them once at the edge rather than per-application where you can — nginx or Apache config, your CDN's rules, or your framework's header configuration. Setting them in application code means every new route is a chance to forget.

Check what you currently send

Our free security header checker reports which of these headers your site sends, which are missing, and grades the result — no signup. It also flags an exposed X-Powered-By, a wildcard CORS policy and known vulnerabilities in the JavaScript libraries it detects.

Headers are one layer. For the rest, see our website security checklist and guide to HTTPS and SSL.

security headersCSPHSTSX-Frame-Optionsweb securitysiteIQ
C
Written by
Codaiman Admin

Part of the Codaiman team — building AI-powered digital solutions and sharing insights on web development, mobile apps, and the future of technology.