Security Headers Explained
HTTP security response headers instruct browsers how to handle sensitive content, preventing cross-site scripting, framing attacks, cross-origin window leaks, and unencrypted downgrade attempts.
1. Strict-Transport-Security (HSTS)
What it does: Enforces HTTPS on every subsequent visit, blocking man-in-the-middle SSL stripping and cookie hijacking.
Recommended value:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Evaluation rule: A max-age below 15552000 (6 months) deducts -3 points; we recommend at least 31536000 (1 year). Missing includeSubDomains or preload are surfaced for awareness only with no score penalty.
2. Content-Security-Policy (CSP)
What it does: Restricts which scripts, styles, objects, base URIs, and frames may load, neutralizing Cross-Site Scripting (XSS) and data exfiltration.
Recommended strong baseline:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none';
Evaluation rule: Policies using 'unsafe-inline', 'unsafe-eval', *, data:, or http: in script-src (or default-src when script-src is omitted), or missing object-src 'none' / base-uri, receive a Weak (-5) status. Sending Content-Security-Policy-Report-Only alone counts as missing enforcing CSP (-10), though it is the safest way to test a new policy before enforcing it.
3. X-Frame-Options
What it does: Prevents unauthorized embedding inside <iframe> elements, protecting users against clickjacking.
Recommended value:
X-Frame-Options: DENY
Note: Modern browsers honor the CSP frame-ancestors 'none' directive alongside or instead of XFO.
4. X-Content-Type-Options
What it does: Prevents the browser from MIME-sniffing a response away from the declared Content-Type, stopping malicious script execution from uploaded files.
X-Content-Type-Options: nosniff
5. Referrer-Policy
What it does: Protects user privacy by ensuring sensitive URL tokens or path segments are not leaked to external third parties when following outbound links.
Referrer-Policy: strict-origin-when-cross-origin
6. Permissions-Policy
What it does: Disables unneeded browser capabilities such as device camera, microphone, and geolocation APIs across your site.
Permissions-Policy: camera=(), microphone=(), geolocation=()
7. Cross-Origin-Opener-Policy (COOP)
What it does: Isolates the top-level browsing context from cross-origin windows opened via links or window.open, mitigating cross-origin window leaks and side-channel attacks.
Cross-Origin-Opener-Policy: same-origin
Note: Recommended value is same-origin (note that strict COOP can affect popup-based OAuth flows; use same-origin-allow-popups only when external popups require window.opener).
How to Fix It (10 Hosting Platforms)
Select your hosting provider, framework, or web server below to copy a complete baseline header configuration. Always test strict CSP policies in Content-Security-Policy-Report-Only mode before enforcing.
# /etc/nginx/conf.d/security.conf # Warning: Test the baseline Content-Security-Policy in Content-Security-Policy-Report-Only mode first before enforcing. add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; add_header Cross-Origin-Opener-Policy "same-origin" always; # Test in report-only mode first: Content-Security-Policy-Report-Only add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none';" always; server_tokens off;
DNS, Email Trust, DNSSEC & Expiry
Email authentication standards prevent threat actors from forging messages using your domain name, while DNSSEC and domain registration monitoring guard infrastructure integrity.
SPF (Sender Policy Framework)
Published as a DNS TXT record at your apex domain. SurfaceScan follows include and redirect records recursively to enforce the RFC 7208 limit of 10 DNS-querying terms (include, a, mx, ptr, exists, redirect). Publishing multiple v=spf1 records or exceeding 10 lookups breaks SPF (-5). Ending with +all or ?all allows anyone to send mail as your domain (-10); use ~all or -all.
v=spf1 include:_spf.google.com ~all
DKIM (DomainKeys Identified Mail)
DKIM attaches a cryptographic RSA or Ed25519 signature to outgoing email headers. SurfaceScan probes 10 common public selectors (default, google, selector1, selector2, k1, k2, s1, s2, mail, dkim) at <selector>._domainkey.<domain>. Because organizations often configure custom/private selectors, an unfound result is informational only with zero score deduction.
DMARC (Domain-based Message Authentication)
Published at _dmarc.<domain>. Specifies what receiving mail servers should do when SPF/DKIM validation fails. p=none merely monitors, whereas p=quarantine or p=reject actively blocks spoofed emails.
v=DMARC1; p=reject; rua=mailto:[email protected]; pct=100
CAA (Certification Authority Authorization)
Restricts which certificate authorities are allowed to issue SSL certificates for your domain, eliminating rogue CA issuance risks.
example.com. IN CAA 0 issue "letsencrypt.org"
DNSSEC & Domain Registration Expiry (RDAP)
SurfaceScan queries Cloudflare DNS-over-HTTPS (AD flag) to note whether DNSSEC validation is active (informational, neutral status). For domain registration hygiene, we query public RDAP servers via rdap.org: an expiration within 30 days deducts -5 points, an expired registration deducts -10, and unsupported TLDs report Unknown with no deduction.
TLS & Certificate Security
Transport Layer Security (TLS) encrypts all communication between web browsers and your origin server:
- Modern Protocols: Only TLSv1.3 and TLSv1.2 should be enabled. Legacy protocols (SSLv3, TLSv1.0, TLSv1.1) are cryptographically vulnerable and must be disabled.
- Key Sizes: RSA keys must be at least 2048 bits in length (4096-bit recommended for higher security). Modern Elliptic Curve certificates (ECDSA P-256) provide strong protection with faster handshakes.
- Automated Renewal: Automated ACME clients (such as Certbot or Caddy) renew certificates before reaching 14 days to expiration, preventing browser security warnings.
Subdomain Takeover Defense
Subdomain takeover occurs when a DNS record (typically a CNAME) points to a third-party service provider (such as GitHub Pages, Heroku, AWS S3, or Shopify) that has been deleted or unclaimed.
The Danger
An attacker can register the abandoned handle on the cloud provider and claim complete control over your subdomain, allowing them to intercept session cookies, execute malicious scripts, and conduct spear-phishing campaigns.
Remediation: Whenever you decommission a cloud asset, immediately remove the corresponding DNS CNAME or ALIAS record from your DNS registrar.
How Scoring Works
Every domain starts at a baseline score of 100 points. Deductions are subtracted for observed weaknesses and floored at 0 (grades: A+ ≥ 97, A ≥ 90, B+ ≥ 80, B ≥ 70, C ≥ 60, D ≥ 50, F < 50):
| Check | Condition | Deduction |
|---|---|---|
| SSL / TLS Certificate | Port 443 unreachable, expired, untrusted, TLS 1.0/1.1, or < 2048-bit RSA | -40 |
| SSL / TLS Expiration | Certificate expires in fewer than 14 days | -15 |
| Subdomain Takeover | Dangling CNAME record pointing to an unclaimed cloud endpoint | -20 |
| Strict-Transport-Security (HSTS) | Missing Strict-Transport-Security response header | -10 |
| Weak HSTS max-age | Strict-Transport-Security max-age is below 15552000 (6 months); 31536000 recommended | -3 |
| Content-Security-Policy (CSP) | Missing Content-Security-Policy (or Report-Only only) | -10 |
| Weak Content-Security-Policy | CSP allows unsafe-inline, unsafe-eval, *, data:, http: in script-src/default-src, or lacks object-src 'none' or base-uri | -5 |
| Clickjacking Protection | Missing both X-Frame-Options and CSP frame-ancestors directive | -5 |
| X-Content-Type-Options | Missing X-Content-Type-Options: nosniff | -5 |
| Referrer-Policy | Missing Referrer-Policy response header | -3 |
| Permissions-Policy | Missing Permissions-Policy response header | -2 |
| Cross-Origin-Opener-Policy (COOP) | Missing Cross-Origin-Opener-Policy header (same-origin recommended) | -2 |
| HTTP to HTTPS Redirection | Plain HTTP does not automatically redirect to HTTPS | -5 |
| Insecure CORS Policy | Wildcard CORS with credentials or arbitrary Origin reflection | -10 |
| Weak Cookie Flags | Set-Cookie missing Secure, HttpOnly, or SameSite attribute | -3 |
| Third-Party Script Integrity (SRI) | External third-party <script> loaded without integrity attribute | -3 |
| Active Mixed Content | HTTPS page embeds active subresources (<script>, stylesheet, <iframe>) over insecure http:// | -5 |
| Missing SPF Record | No v=spf1 DNS TXT record published | -5 |
| Broken SPF Policy | Multiple SPF records (>1) or exceeding 10 recursive DNS lookups (SPF will fail) | -5 |
| Permissive SPF (+all / ?all) | SPF ends with +all or ?all (anyone can send mail as your domain) | -10 |
| Missing or Weak DMARC | No _dmarc TXT record or policy set to p=none (monitoring only) | -5 |
| DNS CAA Records | No Certificate Authority Authorization (CAA) record published | -2 |
| RFC 9116 security.txt | Missing or expired /.well-known/security.txt policy | -2 |
| Domain Registration Expired | RDAP reports the domain registration expiration date is in the past | -10 |
| Domain Registration Expiring Soon | RDAP reports domain registration expires in under 30 days | -5 |
| HSTS includeSubDomains / preload | Missing includeSubDomains or preload tokens (informational only) | Informational (0) |
| DNSSEC Validation | DNSSEC AD flag queried via Cloudflare DNS-over-HTTPS (informational only) | Informational (0) |
| DKIM Selector Probe | Probes 10 common DKIM selectors; custom private selectors may not appear (informational) | Informational (0) |
| RDAP Availability | If RDAP is unavailable for a TLD or fails, status shows Unknown with no penalty | Informational (0) |
| MTA-STS / TLS-RPT / BIMI | Checks _mta-sts, _smtp._tls, and default._bimi DNS TXT records (informational) | Informational (0) |
| Server / Framework Version Disclosure | Flags exposed software versions in Server or X-Powered-By response headers (informational) | Informational (0) |
Glossary of Terms
- SNI (Server Name Indication)
- A TLS extension where the client indicates the hostname it wants to connect to at the start of the handshake.
- COOP (Cross-Origin-Opener-Policy)
- An HTTP response header that ensures top-level documents do not share a browsing context group with cross-origin documents.
- RDAP (Registration Data Access Protocol)
- The structured JSON successor to WHOIS used to inspect domain registration status and expiration dates.
- RFC 9116 (security.txt)
- The IETF standard establishing a well-known URI for organizations to publish coordinated security vulnerability disclosure policies.