PAKTI Book a call
← Back to blog

The security headers most sites never send — and what each one actually stops

  • hardening
  • headers
  • basics

Run curl -I against almost any small business website and you’ll see the same thing: a handful of caching headers, maybe a server version string it shouldn’t be revealing, and none of the half-dozen security headers that browsers have supported for years. That’s a strange gap, because security headers are close to free — no new software, no performance cost, one configuration change — and each one removes an entire category of attack rather than a single bug.

A security header is simply an instruction your server attaches to every response, telling the visitor’s browser how to treat your site: what it’s allowed to load, whether it can be embedded elsewhere, whether plain HTTP is ever acceptable. The browser does the enforcement. You just have to ask.

Strict-Transport-Security (HSTS)

HTTPS only protects visitors who actually use it. Without HSTS, someone who types your bare domain makes one unencrypted request first — and on a hostile network (think airport Wi-Fi), that single request is enough for an attacker to intercept the connection and keep the victim on plain HTTP while proxying your real site. This is SSL stripping, and it’s been a standard tool since 2009.

Strict-Transport-Security: max-age=63072000 tells the browser: for the next two years, never contact this domain over plain HTTP, no exceptions. The downgrade window disappears after the first visit.

Content-Security-Policy (CSP)

The most powerful header, and the only genuinely fiddly one. CSP is an allowlist of where content on your pages may come from: scripts only from your own domain, no plugins, no embedding, images only from sources you name.

Its real value is as a second line of defense. Cross-site scripting and injected-malware attacks ultimately work by making a victim’s browser run a script the site owner never intended. A strict CSP means that even when an attacker finds a way to inject something, the browser refuses to execute it — the injection lands, the payload doesn’t fire.

Because CSP blocks whatever it doesn’t recognize, deploying it carelessly can break your own site. The sane path is to start with Content-Security-Policy-Report-Only, which logs violations without enforcing anything, watch for a week, then switch to enforcement.

X-Content-Type-Options and frame-ancestors

Two small ones worth shipping together:

  • X-Content-Type-Options: nosniff stops the browser from second-guessing file types. Historically, browsers would “sniff” a file’s content and could be tricked into executing an uploaded image or text file as script. One header ends the guessing.
  • frame-ancestors 'none' (in your CSP, replacing the older X-Frame-Options) stops other sites from loading yours inside an invisible iframe. That’s the mechanic behind clickjacking — a visitor thinks they’re clicking a button on the attacker’s page while actually clicking something on yours.

Referrer-Policy

When a visitor follows a link from your site, their browser tells the destination where they came from — by default, sometimes including the full URL. If your URLs ever contain anything meaningful (account areas, search queries, password-reset paths), you’re leaking it to every third party your pages link to. Referrer-Policy: strict-origin-when-cross-origin trims that to just your domain name, and is a sensible default for everyone.

How to check your own site

Two minutes, no tools to install: curl -I https://yourdomain.com shows exactly what your server sends, and securityheaders.com grades it and explains every gap. If your site is behind a CDN or a host like Vercel or Netlify, you can usually add all of these in one small config file rather than touching a server.

The honest caveat

Headers are seatbelts, not brakes. They limit how badly things go wrong when something else fails — they don’t patch the vulnerable plugin, fix the weak admin password, or validate your form input. A site can score an A+ on headers and still be trivially compromised through an outdated component. Ship the headers because they’re nearly free and genuinely effective, then keep doing the unglamorous work — patching, monitoring, backups — that the score doesn’t measure.