Tools · Web security

Security Headers Checker

Your server answers every single visitor with a set of HTTP headers - and several of them exist purely to make attacks against your users harder. Most sites are missing half of them. Here's how to check yours.

Check your headers

The fastest way to see where you stand is the free scan - paste your URL and it checks every header below, flags what's missing, and shows what each one was protecting. Run it against your real production URL, not a staging copy.

You can also check by hand in seconds. Open your browser's developer tools, go to the Network tab, reload the page, click the main document request (the first one), and read the response headers. Or from any terminal: curl -sI https://yoursite.com prints the full set.

Check more than the homepage. Each redirect - http to https, www to non-www - gets its own response and its own headers, and one missed redirect can quietly strip HSTS. And if you sit behind a CDN, check what's actually served at the edge, not just what your origin sends.

The headers that matter

Eight headers cover the vast majority of real-world risk. Here's what each one does and what a missing one costs you.

Strict-Transport-Security

Tells the browser to only ever talk to your site over HTTPS for the next max-age seconds, and to refuse to fall back to HTTP. That's precisely the protection against SSL-stripping, where a man-in-the-middle quietly downgrades a visitor to an unencrypted connection and reads or alters the traffic. A typical value: max-age=31536000; includeSubDomains. Deploy it only once HTTPS works everywhere on your domain - browsers cache this policy aggressively, and a mistake here can lock visitors out.

Content-Security-Policy

The big one. CSP tells the browser exactly which sources are allowed to load scripts, styles, frames, and everything else - so a script injected from an attacker's domain simply doesn't run. It's the strongest defense-in-depth against cross-site scripting that exists. It's also the one that takes real tuning: your analytics, fonts, tag managers, and payment iframes all need to be allowed explicitly. Start with Content-Security-Policy-Report-Only, watch the reports for a couple of weeks, fix what breaks, then switch to enforcing.

X-Frame-Options and frame-ancestors

Controls who can embed your pages in an iframe. Without it, an attacker can load your site invisible inside their own page and trick logged-in users into clicking things they can't see - clickjacking. X-Frame-Options: DENY or SAMEORIGIN covers older browsers; the modern equivalent is the CSP directive frame-ancestors 'self'. Set one of them, and if you already enforce a CSP, frame-ancestors is the cleaner choice.

X-Content-Type-Options: nosniff

Stops the browser from "sniffing" content types and overriding what the server declared. The classic failure: a site lets users upload files, an attacker uploads a file full of JavaScript, the server serves it with a generic content type, and the browser decides it's executable anyway. One word - nosniff - closes that entire class of MIME-confusion attacks. There is no reason not to set it.

Referrer-Policy

Every time a visitor follows a link away from your site, or your page loads a third-party resource, the browser may send the current URL along in the Referer header. If your URLs carry tokens, IDs, or anything else sensitive, that leaks to third parties. Referrer-Policy: strict-origin-when-cross-origin keeps the origin on cross-site requests but drops the full path - a sane default for almost any site.

Permissions-Policy

Lets you disable powerful browser APIs your site never uses: camera, microphone, geolocation, USB, accelerometer. If your own code never calls them, there's no reason injected code should be able to either. Permissions-Policy: camera=(), microphone=(), geolocation=() is cheap insurance.

Cross-Origin-Opener-Policy and Cross-Origin-Resource-Policy

Briefly: COOP isolates your pages from cross-origin windows that open them - part of the Spectre-era defenses, and a requirement for cross-origin isolation in high-security apps. CORP declares which other sites are allowed to load your resources. Set them if you can; they're hardening, not critical.

Server header hygiene

This one isn't a protection - it's the opposite. Default server configs advertise exact versions: Server: nginx/1.18.0, X-Powered-By: PHP/8.1.4. That hands every scanner your version number to look up known CVEs against. Trim or remove them. It won't stop a determined attacker, but stop doing their reconnaissance for them.

How to read the results

Think in two tiers. Critical: Strict-Transport-Security, Content-Security-Policy, X-Frame-Options or frame-ancestors, and X-Content-Type-Options. Missing any of these is a real, exploitable gap under the right conditions. Nice-to-have: Referrer-Policy, Permissions-Policy, COOP, CORP, and a quiet Server header.

The most common finding by far is no CSP at all - most sites simply never set one, which leaves one reflected XSS a single script tag away from full account compromise. The second most common: a CSP stuck in Report-Only mode forever, technically present but protecting nothing.

Don't chase a perfect scanner grade by pasting someone else's policy. A CSP that breaks your checkout gets rolled back within a day. A working, slightly looser policy that you tighten over time beats an ideal one that never ships.

Fixing them

Headers are set in your web server or CDN config, not in application code - which is good news, because it's a handful of lines:

  • nginx: add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - one add_header per policy
  • Apache: Header always set Content-Security-Policy "default-src 'self'"
  • The always keyword matters: without it, error responses can be served without your headers.
  • Only CSP has a meta-tag equivalent, and it's weaker - no frame-ancestors, no report-only mode, and no protection until the HTML starts parsing. Set headers at the server.
  • Behind Cloudflare or another CDN? It can add and modify headers too (Cloudflare: Transform Rules, then Modify Response Header). But the CDN layer can also override or strip what your origin sends - after any deploy, re-check with curl -sI to see what visitors actually get.

Headers are hardening, not testing

Get these right and you've made whole attack classes measurably harder. But headers don't touch your actual application: SQL injection, broken access control, broken authentication, business-logic flaws - all of them work exactly the same against a perfect headers score. Hardening reduces risk at the edges; it doesn't test what's in the middle.

So don't let a green scan stand in for an assessment. If you want the application itself attacked the way an attacker would attack it, look at web application penetration testing - manual testing, not a re-badged scanner. If you're weighing how much testing you actually need, the difference between a penetration test and a vulnerability scan is worth five minutes. More free checks live on the tools page, and if you'd rather just talk it through, contact me.

Header questions

Content-Security-Policy gives you the biggest single win, because it's the main defense-in-depth against cross-site scripting. But it's also the hardest one to get right. Strict-Transport-Security has the best effort-to-value ratio: one line, and it blocks SSL-stripping attacks. If you only fix two things, fix those two.

No. They add a few hundred bytes to each response - less than most images on the page. There's no measurable processing cost on the client beyond parsing the header once per response. The performance cost is effectively zero.

Only Content-Security-Policy has a meta-tag version, and it's weaker: no frame-ancestors, no report-only mode, and no protection until the HTML starts parsing. The rest - HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy - are HTTP-only by design. Set them in your web server or CDN config.

Then set them at the CDN. Cloudflare can add or modify response headers with Transform Rules, and most CDNs have an equivalent. Whichever layer serves the response last wins, so after any deploy, re-check with curl -sI to confirm what visitors actually receive.

No. They harden the browser against whole attack classes like XSS and clickjacking, but they don't fix anything in your application - SQL injection, broken access control, and business-logic flaws all work regardless of your headers. Headers are one layer; the application behind them still needs real testing.

Headers clean but still unsure about the app behind them?

Headers are the seatbelt; the code is the car. Test the application itself.

Contact