"These four systems sit below your app code. TLS proves you're on a trusted channel. Security headers are infra config — set once, apply everywhere. A Service Worker is your client-side cache CDN. SRI and lockfiles guard the supply chain."
Three guarantees: confidentiality (encrypt) · integrity (tamper detection) · authenticity (cert proves server identity)
NOT protected server bugs · client XSS · who you talk to (IP visible) · timing/volume
Strict-Transport-Security: max-age=63072000; includeSubDomains
Browser upgrades to HTTPS unconditionally — no HTTP hits the network. Preload list = even first visit is HTTPS. Preload is hard to undo — all subdomains must be HTTPS-ready first.
Active (JS/CSS/iframes over HTTP) = always blocked. Passive (images) = Chrome auto-upgrades or blocks. Fix: upgrade-insecure-requests in CSP or protocol-relative URLs.
| Header | What it stops |
|---|---|
X-Content-Type-Options: nosniff | MIME sniffing — browser executing JS served as text/plain |
Referrer-Policy: strict-origin-when-cross-origin | Full URL leaking to third parties via Referer |
Permissions-Policy: geolocation=(), camera=() | Malicious embedded scripts requesting browser APIs |
Strict-Transport-Security | HTTP downgrade |
Content-Security-Policy (L19) | XSS execution |
frame-ancestors 'self' (L19) | Clickjacking |
Audit: securityheaders.com
install (precache assets) → waiting (old SW still active) → activate (clean old caches) → fetch (intercept requests)
By default a new SW waits until all tabs using the old SW close. skipWaiting() + clients.claim() override this — useful but risky (see trap).
Workbox wraps these patterns (Google's SW library).
<script src="https://cdn.example/react.min.js" integrity="sha384-abc123..." crossorigin="anonymous"></script>
Protects CDN compromise — hash mismatch → blocked
Doesn't protect bundled npm deps (inside your JS)
crossorigin="anonymous" required — SRI uses a CORS fetch
package-lock.jsonAttack vectors: typosquatting (lodahs), dependency confusion (public pkg shadows private), compromised maintainer (event-stream 2018)
CSP (script-src + nonce + frame-ancestors) · HSTS · X-Content-Type-Options: nosniff · Referrer-Policy: strict-origin-when-cross-origin · Permissions-Policy: geolocation=(),camera=() · X-Frame-Options: SAMEORIGIN (legacy fallback)
skipWaiting() mid-session skew: Calling skipWaiting forces the new SW active while an old-SW page is still open. Old page requests chunk URLs from the new deploy → 404 / white screen if old chunks are deleted. Fix: content-hash filenames (old + new coexist) + prompt user to reload.
npm install ≠ npm ci: npm install can update the lockfile if a newer semver-compatible version is published (including a malicious one). npm ci fails if the lockfile doesn't match — always use it in pipelines.