Web and Application Security

Security Headers Checklist: CSP and HSTS for Client Websites

Most customer websites are missing HTTP security headers not because anyone decided against them, but because no one added them and nothing ever flagged the gap. A handful of headers close off entire categories of attack for close to zero engineering cost — the only real risk is turning on the strictest one carelessly and breaking the site. Here is the rollout order that avoids that.

What these headers actually control

HTTPS protects data in transit between a browser and a server. Security headers protect something different: what the browser is allowed to do once a page has actually loaded — which scripts can run, whether the page can be framed by another site, whether the browser should ever fall back to an unencrypted connection. A site with flawless TLS and no security headers is still exposed to the exact problems headers exist to prevent.

That gap is common because headers are invisible in normal use. A missing header does not break the site or show an error; it just removes a layer of browser-enforced protection that was never there to notice in the first place.

Start here: near-zero-risk headers

Strict-Transport-Security (HSTS) tells the browser to always use HTTPS for the domain going forward, closing off the window where a user might be downgraded to an unencrypted connection. For a site that already only serves HTTPS, this has essentially no downside.

X-Content-Type-Options: nosniff stops the browser from guessing a file's type based on its content instead of trusting the declared type, which closes off a class of attacks that rely on that guessing behavior. It is a single line with no realistic compatibility impact.

Referrer-Policy controls how much of the current URL gets sent along when a user clicks a link to another site — useful when URLs contain anything sensitive, and low-risk to set to a conservative value.

Next: clickjacking protection

X-Frame-Options, or the equivalent frame-ancestors directive in CSP, controls whether the site can be loaded inside a frame on another page — the mechanism behind clickjacking, where a page is invisibly framed and a user is tricked into clicking something they cannot see. Most sites have no legitimate reason to be framed by another domain, which makes this a low-risk header to enable broadly, with an explicit exception for the rare site that is deliberately embedded elsewhere.

Last: Content-Security-Policy, and why it goes last

CSP is the highest-value header on this list and the one most likely to break something if rushed. It works by declaring every source a page is allowed to load scripts, styles, images, and fonts from, and blocking everything not on the list — which is exactly what makes it powerful against cross-site scripting, and exactly what makes an incomplete policy break real functionality: analytics tags, embedded widgets, payment forms, and web fonts all come from third-party domains that have to be explicitly listed.

Always start with Content-Security-Policy-Report-Only instead of the enforcing header. Report-only evaluates the policy and logs what it would have blocked without actually blocking it, which surfaces every legitimate source the policy is missing. Run it for a couple of weeks, fix the gaps the reports reveal, and only then switch to the enforcing header.

A rollout order that avoids breaking a live customer site

  • Enable HSTS, X-Content-Type-Options, and Referrer-Policy — low risk, immediate.
  • Enable X-Frame-Options or CSP frame-ancestors, after confirming the site is not deliberately framed elsewhere.
  • Draft a CSP based on the site's actual third-party resources and deploy it in report-only mode.
  • Review report-only violations for two to four weeks and adjust the policy.
  • Switch CSP to enforcing once reports are clean.
  • Re-check after any hosting, CDN, or platform migration — headers set at the server or CDN layer do not automatically carry over.

Tracking coverage across a portfolio, and catching regressions

Headers configured correctly during a website rebuild have a specific way of quietly disappearing: a CDN migration, a hosting provider change, or a new reverse proxy in front of the site, none of which necessarily carry over header configuration set at the previous layer. Nothing about the site visually changes when this happens, which is exactly why it needs to be checked on a schedule rather than assumed to still be in place because it was correct at the last review.

SecurityScore.me checks HTTPS, TLS configuration, and security headers as part of externally observable web posture for every registered customer website, alongside certificate validity and technology fingerprints. See domain and website monitoring for the full set of web and TLS checks, and the MSP security platform overview for how these findings sit alongside Microsoft 365 posture in one customer workspace.

Frequently asked questions

Learn more

Track security header coverage across every client website