Free reference

Security headers and TLS cheat sheet

Headers with the value to send rather than a vague description of it, and the openssl and curl invocations for checking what actually went over the wire.

RESPONSE HEADERS

Strict-Transport-Securitymax-age=31536000; includeSubDomains; preload
Content-Security-Policydefault-src 'self'; object-src 'none'; frame-ancestors 'none'
X-Content-Type-Optionsnosniff
Referrer-Policystrict-origin-when-cross-origin
Permissions-Policygeolocation=(), camera=(), microphone=()
Cross-Origin-Opener-Policysame-origin
X-Frame-OptionsDENY
Cache-Control on anything sensitiveno-store

OPENSSL

See the handshake and the chainopenssl s_client -connect host:443 -servername host
Just the expiry dates... </dev/null 2>/dev/null | openssl x509 -noout -dates
Read a local certificateopenssl x509 -in cert.pem -noout -text
Names the cert actually coversopenssl x509 -in cert.pem -noout -ext subjectAltName
The full chain as sentopenssl s_client -connect host:443 -showcerts
Do this key and cert matchopenssl x509 -noout -modulus -in cert.pem | openssl sha256 openssl rsa -noout -modulus -in key.pem | openssl sha256

CURL

curl -sSI https://host headers only
curl -sSv https://host -o /dev/null the TLS detail
curl --resolve host:443:1.2.3.4 https://host test before DNS moves

COOKIE FLAGS

SecureHTTPS only
HttpOnlyno JavaScript access
SameSite=Laxthe sane default
SameSite=Strictno cross-site at all
SameSite=Nonerequires Secure

WHAT IT USUALLY IS

The browser trusts it, your service does not. Missing intermediate. Serve the full chain.

Works by IP, fails by name. SNI, or the name is not in the SAN.

The parts people get wrong

These are the distinctions that cost real time. They are the reason this sheet exists rather than another list of commands.

Why browsers ignore the certificate Common Name

The Common Name is dead. Browsers read subjectAltName and nothing else. A cert with the right CN and the wrong SAN fails.

HSTS max-age and preload requirements

A max-age under 31536000 is not preload-eligible, and preload is very hard to undo. Be sure before you submit.

Rolling out a Content Security Policy safely

Ship CSP as Content-Security-Policy-Report-Only first. Read the reports for a week. Then enforce.

SameSite=None cookie is not being set

SameSite=None without Secure is dropped silently. No error, no cookie, a very long afternoon.

Security headers on error pages and redirects

A header only protects the response carrying it. Set them on errors and redirects too, not just the happy path.

A certificate error that is not an expired certificate

Certificate expiry is not the usual cause of a certificate error. Chain order and missing intermediates are.

A wildcard certificate expired

A wildcard expired. Check every host that used it, not just the one that paged you.

Certificate works on my machine only

Trusted on your laptop and nowhere else? You installed that CA once and forgot about it.

X-Frame-Options vs CSP frame-ancestors

X-Frame-Options is legacy. CSP frame-ancestors supersedes it, but send both until you are sure nothing old is calling.

Other cheat sheets