Security headers are unusual as a defense mechanism: they're not something your server enforces, they're instructions your server sends that the visitor's browser enforces on its own. That matters because it means these headers still protect a visitor even if there's a bug somewhere else in your application — they're a second, independent layer, not a substitute for writing safe code, but a backstop for when that code isn't perfect. Nothing ever is.
Our Security Headers Checker fetches a page's response headers and checks for six of them specifically. This walks through what each one actually does, using the same descriptions the tool itself reports.
Using the tool#
Enter a URL, and we make the same kind of request a browser would, then read back exactly what the server sent. This has to happen server-side — a browser can't inspect another site's response headers itself via JavaScript, which is itself one of the security boundaries these headers help enforce.
Strict-Transport-Security (HSTS)#
Forces the browser to only ever connect to your site over HTTPS, even if a visitor types http:// or clicks an old plain-HTTP link.
Without it, the very first request a browser makes can go out over plain HTTP before any redirect to HTTPS happens — and that one unencrypted request is a real opening. On public wifi, an attacker positioned between the visitor and your server can intercept that first plaintext request and simply never let the HTTPS redirect happen, silently downgrading the entire session and reading everything that follows, cookies included. This is a real, well-documented attack class (SSL stripping), and HSTS is what closes it: once a browser has seen the header once, it refuses to even attempt an HTTP connection to that domain again, for as long as max-age says.
Strict-Transport-Security: max-age=31536000; includeSubDomains. The preload directive goes further — it gets your domain baked directly into browsers themselves, before they've even made a first request — but it's slow to undo if you ever need to serve plain HTTP again, so treat it as a deliberate, harder-to-reverse step rather than a default.Content-Security-Policy (CSP)#
Restricts which scripts, styles, images, and other resources a page is allowed to load — and it's the single biggest defense against cross-site scripting (XSS) that exists at the browser level.
XSS works by getting the browser to execute attacker-controlled JavaScript in the context of your page — through an unsanitized comment field, a URL parameter reflected into HTML, anywhere user input ends up somewhere a browser will parse it as code. Once that happens, the attacker's script can read cookies, submit forms as the logged-in user, or quietly exfiltrate whatever's on the page. A correctly scoped CSP means that even if an attacker successfully injects a <script> tag, the browser simply refuses to run it, because the policy only allows scripts from sources you explicitly named.
Content-Security-Policy-Report-Only first: it reports what would have been blocked without actually blocking anything, so you can see the real impact before switching to enforcement.X-Frame-Options#
Stops your site from being loaded inside a hidden <iframe> on someone else's page — the defense against clickjacking.
A clickjacking attack layers your real page underneath an invisible iframe, with a fake "Click here to win" button positioned exactly over a real, sensitive control on your page — a bank transfer confirmation, an account-settings toggle, a purchase button. The visitor thinks they're clicking the fake button; they're actually clicking your real page underneath it, fully logged in. X-Frame-Options: DENY (or SAMEORIGIN, if you legitimately need to frame your own pages) tells the browser to refuse to render the page inside any frame at all, which makes the whole attack impossible regardless of what the attacker's page does.
CSP's frame-ancestors directive does the same job and is the more modern, flexible version — but X-Frame-Options is still worth setting directly, since it's supported by browsers that predate CSP.
X-Content-Type-Options#
A single value, nosniff, that stops browsers from guessing a file's type instead of trusting the server's declared Content-Type.
Older browsers would "sniff" a file's actual content to guess its type — useful for a server that mislabels a file, but exploitable: a file uploaded with an image extension but crafted to contain HTML/script content could get sniffed as HTML and executed, instead of being displayed as the harmless image it claimed to be. This is a legacy-era attack surface at this point, but the header costs nothing to set and there's no real downside to it.
Referrer-Policy#
Controls how much of your page's URL gets sent to whatever site a visitor clicks a link to next.
By default, browsers send the full referring URL — including query strings — to the destination site's server logs and analytics. If a page's URL happens to contain anything sensitive (a password-reset token, a session identifier, an internal search term, an account ID), clicking any outbound link on that page leaks it to a third party you never intended to share it with. Referrer-Policy: strict-origin-when-cross-origin is a sane modern default: it sends the full URL to same-site destinations (where it's genuinely useful), but trims cross-site referrers down to just the origin.
Permissions-Policy#
Explicitly turns off browser features — camera, microphone, geolocation, and others — that your site never uses.
Even if your own code never asks for the camera, every third-party script you embed (an ad, a widget, an analytics snippet) runs with the same permissions your page has by default, unless you've explicitly restricted them. A compromised or malicious third-party script could attempt to request access to a sensitive device feature on your page's behalf. A minimal policy like Permissions-Policy: camera=(), microphone=(), geolocation=() disables features your site doesn't use, closing that door regardless of what any embedded script tries.
The flip side: headers that leak information#
Our checker also flags two headers separately — Server and X-Powered-By — but for the opposite reason: these reward absence, not presence. A response like Server: nginx/1.18.0 or X-Powered-By: Express hands an attacker your exact software and version for free, which lets them skip reconnaissance entirely and go straight to checking known CVEs for that specific release. Removing these headers doesn't make your server more secure by itself, but it does remove a shortcut for anyone probing it.
Where to start, if you can only fix a couple of things#
HSTS and CSP carry the most weight — they close the two attack classes (protocol downgrade, and script injection) with the widest real-world blast radius. X-Frame-Options and X-Content-Type-Options are close to zero-risk to add and take a minute each. Referrer-Policy and Permissions-Policy are lower urgency but still worth doing — they're both entirely safe defaults with no realistic downside.
What headers don't cover#
These are all passive, browser-enforced protections — they do nothing against attacks that never involve a browser at all: SQL injection against your backend, credential-stuffing login attempts, a scraper hammering your API, or a bot flooding a specific endpoint. That's a server-side problem, which is what a WAF and rate limiting exist for.
Apply all of this without touching your app's code
ShieldIngress applies security headers at the edge, in front of your application — no per-framework config, no redeploy required to change a policy.