Running it

Security Headers Checklist for Business Sites

Seven HTTP response headers that close the most common attacks on a business website, what each one actually does, and how to check the ones you are already sending.

Illustration: a shield of six ticked bars in front of a browser window

Headers are the cheapest security you will ever deploy

Every response your server sends carries headers. A handful of them tell the browser how to treat your site, and setting them correctly closes off a whole class of attacks without touching a line of application code.

They are not a substitute for the rest of security. They do nothing about a weak password, an unpatched dependency or an endpoint with no authorisation check. What they are is the highest return per hour of work available on a business website, and most business websites send almost none of them.

You can see what you are sending right now with the security headers checker, which fetches your live URL and reports what came back. Everything below is one of the things it looks for.

Security Headers Checker report for bitssolved.com showing six of six recommended headers set
The report this site returns for itself. Publishing a checker you fail is not a good look, so all six are set.

Start with HTTPS, then make it non-negotiable

HTTPS is assumed at this point, but two things around it are routinely left half done.

The first is the certificate itself: valid, not expiring in three weeks, and covering every hostname you actually serve, which usually means both example.com and www.example.com. Certificates that expire on a Sunday are a genuine cause of outages. The SSL checker will tell you what yours covers and when it expires.

The second is Strict-Transport-Security, usually called HSTS. Redirecting HTTP to HTTPS still allows a first insecure request, and that first request is where an attacker on the same network can intervene. HSTS tells the browser never to attempt HTTP for your domain again:

HTTP header
Strict-Transport-Security: max-age=31536000; includeSubDomains

One warning worth respecting. includeSubDomains applies to every subdomain, including internal ones you may have forgotten about, and the browser will remember the instruction for the full max-age. Start with a short max-age, confirm nothing broke, then raise it. The HSTS checker shows what you are currently sending.

Content-Security-Policy

CSP is the most powerful of these headers and the most work, because it is the one that says which sources of script, style, image and font the browser is permitted to load. Done properly it means an injected <script> tag does not execute, which is the difference between a defacement and a breach.

Illustration: a gate before a browser lets tagged scripts through and stops an untagged one
Content-Security-Policy is an allowlist: scripts from sources you named run, and everything else is stopped at the gate.

It is also the one that breaks sites when it is pasted in from a blog post, so do it in this order:

  1. Deploy it as Content-Security-Policy-Report-Only first. The browser reports what would have been blocked and blocks nothing.
  2. Live with that for a week and read the reports. You will discover third-party scripts nobody remembers adding.
  3. Tighten until the report is quiet, then switch to enforcing.

Avoid unsafe-inline if you possibly can, because it removes most of the benefit. If your site has inline scripts it cannot lose, use a nonce rather than opening the whole category. The CSP analyzer will parse a policy and point out the directives that are weaker than they look.

X-Content-Type-Options

HTTP header
X-Content-Type-Options: nosniff

One line, no configuration, no downside. It stops the browser from guessing that a file is something other than what you said it was, which is how an uploaded file that claims to be an image ends up being executed as script. If you set nothing else from this article, set this.

Referrer-Policy

By default, when a visitor clicks a link off your site, the browser tells the destination which page they came from, including the full URL. On a site with query strings, tokens or internal search terms in URLs, that is a quiet leak to every external site you link to.

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

This sends the full path within your own site, and only the bare domain to anywhere else. It is the sensible default for a business site and it keeps analytics working.

Permissions-Policy

This declares which browser capabilities your pages are allowed to use. A business website almost never needs the camera, the microphone, geolocation or payment APIs, and saying so explicitly means an injected script cannot request them either.

HTTP header
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()

Start from denying everything and add back what the site genuinely uses.

Clickjacking: frame-ancestors, not X-Frame-Options

Clickjacking is loading your site inside an invisible frame on an attacker's page so that a user who thinks they are clicking one thing clicks another. The old defence was X-Frame-Options: DENY. It still works, and it is still worth sending for old browsers, but the modern and more flexible answer is a CSP directive:

HTTP header
Content-Security-Policy: frame-ancestors 'self'

Send both. They cost nothing and they cover different browsers.

Email is a security surface too

Headers protect the website. The other half of a business domain is email, and a domain with no email authentication can be spoofed by anybody, which is how invoice fraud reaches your customers with your name on it.

Three records, all in DNS:

  • SPF lists which servers may send mail as your domain.
  • DKIM signs outgoing mail so the recipient can verify it was not altered.
  • DMARC tells receiving servers what to do when a message fails the first two, and where to send reports.

Check what you publish with the DMARC checker. A great many business domains have SPF, no DKIM, and a DMARC policy of p=none, which requests reports and enforces nothing. That is a reasonable place to start and a poor place to stay. When the symptom is your own mail landing in junk rather than somebody forging you, why business emails go to spam walks the diagnosis in order, including the records your website sends from rather than your mailbox.

The same three records decide whether your own mail is believed, which is why a neglected domain tends to produce the other symptom at the same time: enquiries that never arrive. If that is happening to you, contact form emails going to spam splits it into the three faults it can be and diagnoses each one from the browser.

What this does not cover

Being honest about the limits matters more here than in most subjects, because security is the area where confident marketing does the most damage.

Headers do not authenticate anybody. They do not authorise anybody. They do not patch your dependencies, protect a database with a default password, or stop a member of staff pasting credentials into a message. They close specific browser-level attacks and nothing else.

They are also not a certification. BitsSolved does not hold SOC 2, ISO 27001 or HIPAA attestations, and any vendor who implies that setting headers amounts to compliance is selling something. What we do is set them on everything we deploy, along with TLS, monitoring and backups, and this site passes its own checkers, which is the least you should expect from anybody who publishes a tool like that.

If you want the current state of a site written down rather than guessed at, that is website fixes and maintenance for an existing site, and cloud and DevOps when the answer is in the infrastructure rather than the markup.

Tools mentioned in this post

Want this built properly?

The first call is free and is mostly us asking questions. After it you get the scope in writing and a fixed quote for the first phase.

What happens next

  1. You send the formTell us the problem.
  2. We reply by emailWith any questions.
  3. A free first callThen the scope in writing.
Based inTamil Nadu, India
First callFree, and mostly us asking questions