Why most sites score D or F
If you run securityheaders.com or our SSL Certificate Checker against the top 1,000 small-business websites, roughly 70% will score D or F. Not because the sites are catastrophically insecure — most run on perfectly modern stacks. They score badly because the headers protect against attacks that need explicit opt-in from the site owner, and most owners never opt in.
Six headers, configured correctly, take a typical site from "F" to "A". Most are one-line additions to your nginx or Apache config. None require code changes. None have downside for a normal website.
This article walks through each one with the exact directive to add and the exact thing each one defends against.

1. Strict-Transport-Security (HSTS) — the biggest grade lift
What it does: tells browsers to always use HTTPS for your domain, even if a user types `http://` or clicks an old http link. Once a browser sees the header, it remembers — typically for a year — and refuses to make any non-HTTPS request to your site.
Why this matters: without HSTS, a user on a hostile network (coffee shop wifi, hotel) who types `yoursite.com` into the address bar makes a plain HTTP request first. The server redirects to HTTPS — but the initial request is in cleartext, and an attacker can intercept it before the redirect lands.
The directive:
```
Strict-Transport-Security: max-age=31536000; includeSubDomains
```
In nginx:
```
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
```
In Apache:
```
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
```
For Cloudflare-fronted sites: SSL/TLS → Edge Certificates → HSTS → enable.
Caveat: once you ship HSTS, browsers remember it. If you ever need to roll back to HTTP, you can't — the browser refuses. Test thoroughly on a subdomain first. Most sites should be on HTTPS-only anyway in 2026.
2. X-Content-Type-Options: nosniff — easy win, no downside
What it does: tells the browser to trust the `Content-Type` header you send and not "sniff" the file content to guess the type.
Why this matters: without this header, a browser might decide that a file you served as `text/plain` looks like JavaScript and execute it as JS. If an attacker can upload a "txt" file that the browser auto-executes, that's a stored XSS.
The directive:
```
X-Content-Type-Options: nosniff
```
This has zero downside. Set it on every response. The "but my CMS serves files with wrong Content-Type" excuse means your CMS is wrong; fix it.
3. X-Frame-Options: SAMEORIGIN — clickjacking defense
What it does: prevents your site from being loaded inside an `
Why this matters: clickjacking attacks load your site (e.g. your bank's login page) in an invisible iframe, overlay a fake UI on top of it, and trick the user into clicking through to the real underlying button.
The directive:
```
X-Frame-Options: SAMEORIGIN
```
This allows your own site to embed itself in iframes but blocks anyone else. If you have a legitimate iframe partner (an embed widget), use `Content-Security-Policy: frame-ancestors` instead, which supports a whitelist.
4. Referrer-Policy: strict-origin-when-cross-origin — sensible default
What it does: controls how much of the URL is sent in the `Referer` header when users click links from your site to other sites.
Why this matters: without setting this, your site leaks the full URL of every page a user was on to every external site they click to. Pages with query parameters (which often contain session IDs, search terms, or PII) leak that data to third parties. Analytics platforms see your private pages.
The directive:
```
Referrer-Policy: strict-origin-when-cross-origin
```
This sends the full URL to your own subdomains but only the bare origin (e.g. `https://example.com`) to external sites. Good default for nearly all sites.
5. Permissions-Policy — disable unused browser features
What it does: controls which browser features (camera, microphone, geolocation, USB, etc.) your site is allowed to use. Setting them to `()` disables them entirely.
Why this matters: even if your site doesn't use the camera, a malicious script injected via XSS could request camera access. Permissions-Policy disables the feature at the HTTP layer so the browser never even shows the prompt.
The directive:
```
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()
```
For sites that DO use specific features (e.g. a mapping app uses geolocation), list them with `self` or specific origins:
```
Permissions-Policy: camera=(), microphone=(), geolocation=(self), payment=(), usb=()
```
6. Content-Security-Policy — the hardest, biggest defense
What it does: tells the browser which sources are allowed to load scripts, styles, images, fonts, and frames. It's the most powerful XSS defense available in 2026.
Why this matters: even with input validation and output escaping (which you should do anyway), CSP provides a defense-in-depth layer. If an attacker successfully injects `<script>` into your page, CSP can refuse to execute it because the source doesn't match your whitelist.
The directive (start strict):
```
Content-Security-Policy: default-src 'self'; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; script-src 'self'; font-src 'self' data:; frame-ancestors 'self'; base-uri 'self'; form-action 'self'
```
This is the hardest header to configure correctly because every site has different needs:
The pragmatic approach: start with the strict directive above, then loosen it iteratively as you find pages that break. Most sites land on a usable CSP within 2-3 hours of debugging.
If CSP feels overwhelming, skip it and ship the other five headers. Those five alone take a site from F to B. CSP is the difference between B and A.
The 30-minute audit
For your own site:
1. Run SSL Certificate Checker on your homepage. Note the current grade.
2. Open your web-server config (nginx `.conf`, Apache `.htaccess`, or Cloudflare dashboard if proxied).
3. Add the five easy headers (HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy). 5 minutes total.
4. Reload your web server. Re-run the grader. You should now be at B.
5. Tackle CSP iteratively. Start strict, log violations to a report endpoint, loosen until you stop breaking pages. 1-3 hours depending on site complexity.
Total time: 30 minutes to B grade, an afternoon to A grade.
What these headers do NOT defend against
Be honest about scope:
Real numbers from the audit
In a sample of 100 small-business sites I audited in the past month:
The opportunity is huge. 89% of small-business sites are running a security-headers configuration from 2018 or earlier. The fix is trivial. The default web-server stack is just not opinionated about this, and most owners never look.
The shipping checklist
Corrections + audits
If your site scores well on security headers and you want me to use it as an example in a follow-up article, write to info@krawly.io. If you find an error in the directives above (or a 2026 update I missed), same address.