Tools

Security headers checker

A security headers checker requests a page and reads the HTTP response headers that instruct the browser to restrict what the page may do — Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, Referrer-Policy, Permissions-Policy and the cross-origin isolation headers. It reports which are absent and which are present but permissive, and that second category matters most: a header that is configured to allow everything provides confidence without protection.

What it reads

`Content-Security-Policy` — where scripts, styles and frames may load from. The most consequential of the set.

`Strict-Transport-Security` — force HTTPS, and for how long.

`X-Content-Type-Options` — stop the browser guessing a response's type.

`Referrer-Policy` — how much of the URL is sent when following a link out.

`Permissions-Policy` — which browser features the page may use.

`Cross-Origin-Opener-Policy` and `Cross-Origin-Resource-Policy` — isolation from other origins.

And the disclosure headers: `Server`, `X-Powered-By`.

Present is not the same as effective

A CSP containing `'unsafe-inline'` for scripts permits exactly what CSP exists to block. It is present, and it is close to useless.

A `default-src *` policy allows every origin.

An HSTS header with `max-age=0` disables the protection while appearing configured.

A checker that reports only presence therefore scores such configurations as compliant, which is why the value matters as much as the header name.

Check more than the home page

Headers are frequently set by the web server for static routes and forgotten on application routes or API responses served by a different layer.

A site with perfect headers on `/` and none on `/api/*` has the headers where they are least needed.

What header inspection cannot tell you

Whether the application is secure. Headers reduce the impact of a vulnerability; they do not remove it.

Whether the CSP actually covers the page's real behaviour — only the browser console, on a real page, shows what it blocks.

Anything about the server beyond what it chooses to send.

What VeriFixScan uses

`security.csp`, `security.x_content_type_options`, `security.x_frame_options`, `security.referrer_policy`, `security.permissions_policy`, `security.coop`, `security.corp` and `security.server_disclosure` read the headers of the crawled pages.

`transport.hsts` and `transport.hsts_directives` cover HSTS and its parameters.

The report distinguishes absent from present-and-permissive, because those need different work.

An order that does not break the site

These headers differ enormously in how much they can break, and adding them in order of risk turns a nervous project into an uneventful one.

`X-Content-Type-Options: nosniff` first. It stops the browser guessing a response's type, and the only thing it breaks is a site relying on a mistyped response — which is a defect worth discovering anyway.

`Referrer-Policy: strict-origin-when-cross-origin` next. It is the default in current browsers, so stating it explicitly changes almost nothing while making the behaviour intentional.

Then `frame-ancestors`, via CSP, on a site that is never embedded in an iframe. Verify that assumption first: payment widgets, support tools and marketing previews sometimes embed pages nobody remembers.

`Strict-Transport-Security` once HTTPS is verified on every hostname — with a short `max-age` at first. A long one published over a broken subdomain is honoured by browsers for its full duration and cannot be withdrawn.

`Permissions-Policy` and the cross-origin isolation headers after that, each checked against what the site really uses.

A full `script-src` policy last, and only after a report-only period. It is the header that does the real work and the one that breaks a working site.

Each step is independently useful, so a project interrupted halfway has still improved things rather than leaving a half-configured policy behind.

Reading a report without over-reacting to it

Header checkers grade, and the grade is the least informative thing they produce. A site scoring poorly because it has no CSP and one scoring poorly because its CSP allows every origin are in different situations, and the letter is the same.

Absent is the ordinary state. Most sites send few of these headers, and their absence is a missed mitigation rather than a defect to be alarmed by.

Present and permissive is the finding worth reading carefully, because it is the one that has been mistaken for protection — a CSP with `'unsafe-inline'`, an HSTS header with `max-age=0`, a `default-src *`.

Inconsistent across routes is the finding that indicates a structural problem: the headers are set somewhere that does not cover everything the site serves.

And a header whose value is correct but whose effect nobody has verified in a browser is still unproven. A policy is only known to work when the console is clean on the pages people actually use.

Frequently asked questions

Which header should I add first?
X-Content-Type-Options: nosniff — one line, no risk of breaking anything. Content-Security-Policy gives the most benefit and should be deployed last, in report-only mode first.
Is a missing header a vulnerability?
No. Security headers are defence in depth: they limit what an attacker can do with a vulnerability elsewhere. Their absence is a missed mitigation, not a flaw in itself.
Should I still send X-XSS-Protection?
No. The browser feature it controlled has been removed from modern browsers, and MDN documents the header as non-standard and deprecated.

Sources

Related

VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.

Scan a website