HTTP Cheatsheet

Security Headers

Use this HTTP reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

The full set, and what each one stops

HeaderStopsRecommended value
Strict-Transport-Securityprotocol downgrade, cookie theft on plaintextmax-age=63072000; includeSubDomains; preload
Content-Security-PolicyXSS, injected scripts, data exfiltrationsee below, nonce based
X-Content-Type-OptionsMIME sniffing turning an upload into scriptnosniff
X-Frame-Optionsclickjacking (legacy mechanism)DENY, superseded by CSP frame-ancestors
Referrer-PolicyURL leakage to third partiesstrict-origin-when-cross-origin
Permissions-Policyunwanted camera, mic, geolocation accesscamera=(), microphone=(), geolocation=()
Cross-Origin-Opener-Policycross-window attacks, window.opener abusesame-origin
Cross-Origin-Embedder-PolicySpectre-class cross-origin leaksrequire-corp
Cross-Origin-Resource-Policyyour resources embedded elsewheresame-origin
X-XSS-Protectionnothing, the auditor is removedomit it, or 0
X-Powered-By, Serverversion fingerprintingremove or make them generic

X-XSS-Protection is worth calling out. The browser feature is gone, the header does nothing useful, and its legacy filter mode introduced vulnerabilities of its own. Do not add it.

HSTS

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
DirectiveEffect
max-age=<s>how long the browser refuses plaintext for this host
includeSubDomainsapplies to every subdomain as well
preloadopts into the browser-shipped preload list

Rules that bite:

- HSTS is ignored over plain HTTP, so it must be sent on the HTTPS response. - Roll out with a short max-age (600), verify, then raise it. A long max-age on a host that later needs HTTP is very hard to undo, since only visiting browsers can be told to forget it. - preload is close to permanent. Every subdomain must serve valid HTTPS forever, including internal ones, before you submit. - max-age=0 is how you retract it, and only for clients that visit again.

Content-Security-Policy

The highest-value and highest-effort header. Each directive whitelists sources for one kind of resource.

DirectiveControls
default-srcthe fallback for most fetch directives
script-srcJavaScript, the one that actually stops XSS
style-srcstylesheets
img-srcimages
connect-srcfetch, XHR, WebSocket, EventSource, beacons
font-srcweb fonts
media-srcaudio and video
frame-srcwhat this page may embed
frame-ancestorswho may embed this page, replaces X-Frame-Options
form-actionwhere forms may submit
base-urirestricts <base>, which can otherwise re-root every relative URL
object-srcplugins, always set to 'none'
worker-srcworkers and shared workers
upgrade-insecure-requestsrewrites http subresource URLs to https
report-uri / report-towhere violation reports are posted
Source expressionMeaning
'self'the document's own origin
'none'nothing at all
'unsafe-inline'inline scripts and styles, defeats most of CSP
'unsafe-eval'eval and new Function
'nonce-<random>'only tags carrying this exact per-response nonce
'sha256-<hash>'only inline content matching this hash
'strict-dynamic'trust scripts loaded by already-trusted scripts, ignore host lists
https:any HTTPS origin
https://cdn.example.comone host

A strict, practical policy:

Content-Security-Policy:
  default-src 'self';
  script-src 'nonce-r4nd0mPerRequest' 'strict-dynamic' https: 'unsafe-inline';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  connect-src 'self';
  font-src 'self';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'none';
  form-action 'self';
  upgrade-insecure-requests
<script nonce="r4nd0mPerRequest">/* allowed by the nonce */</script>

The 'unsafe-inline' and https: entries alongside a nonce are deliberate fallbacks for old browsers, which ignore 'strict-dynamic' and nonces. Modern browsers see the nonce and ignore both. The nonce must be cryptographically random and regenerated per response, since a static nonce is no better than 'unsafe-inline'.

Deploy in report-only mode first, collect violations, then enforce:

Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint
Reporting-Endpoints: csp-endpoint="https://example.com/_csp"

Framing, referrers, and permissions

X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'

X-Frame-Options takes DENY or SAMEORIGIN only. The old ALLOW-FROM was never widely supported, so use CSP frame-ancestors when you need an allowlist, and send both headers for older browsers.

Referrer-PolicySends
no-referrernothing, ever
same-originfull URL to your own origin, nothing cross-origin
strict-originorigin only, and nothing on an HTTPS to HTTP downgrade
strict-origin-when-cross-originfull URL same-origin, origin only cross-origin. The default and the right answer
no-referrer-when-downgradethe old default, weaker
unsafe-urlfull URL always, leaks paths and query strings
Permissions-Policy: camera=(), microphone=(), geolocation=(),
  payment=(), usb=(), fullscreen=(self)

() denies a feature everywhere, (self) allows it on your own origin, and (self "https://embed.example.com") extends it to a named origin. Denying what you do not use costs nothing and removes whole permission-prompt attack surfaces.

Cross-origin isolation

The COOP and COEP pair are what unlock SharedArrayBuffer and high-resolution timers, by proving no cross-origin content shares your process.

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
HeaderEffect
COOP: same-originsevers window.opener between your page and cross-origin windows
COEP: require-corpevery cross-origin subresource must opt in with CORP or CORS
CORP: same-originother sites cannot embed this resource at all

Turning on COEP: require-corp will break third-party embeds that do not send Cross-Origin-Resource-Policy: cross-origin, so audit before enabling. Check self.crossOriginIsolated in the console to confirm it took effect.

Auditing what you actually serve

curl -sI https://example.com | grep -iE \
 'strict-transport|content-security|x-content-type|x-frame|referrer-policy|\
permissions-policy|cross-origin|server|x-powered-by'

# see everything, in order, following redirects
curl -sSL -D - -o /dev/null https://example.com

# confirm the redirect chain reaches HTTPS before HSTS is expected to apply
curl -sSIL http://example.com | grep -iE '^HTTP|^location|strict-transport'
FindingFix
No HSTS on the HTTPS responseadd it, short max-age first
CSP contains 'unsafe-inline' in script-src with no nonceXSS is not mitigated, move to nonces
No nosniffan uploaded file can be interpreted as script
Referrer-Policy missingmodern browsers default sensibly, but set it explicitly
Server: nginx/1.18.0drop the version, server_tokens off
Headers present on HTML but not on API responsesset them at the edge, for every route

Two closing points. These headers are defense in depth, not a substitute for output encoding, parameterized queries, and server-side authorization. And a header only protects the responses that carry it, so set them centrally at the proxy or framework layer rather than per route, where one omission becomes the hole.