Commit Graph

3 Commits

Author SHA1 Message Date
Arnas Donauskas
f199b7a7ed
security: baseline response headers (CSP report-only + OWASP set)
Adds a catch-all rule in next.config.ts that merges a set of baseline
security headers into every response — served alongside the existing
Cache-Control rules, not instead of them.

Enforced today:
  - Strict-Transport-Security: 2yr, includeSubDomains, preload-eligible.
    No-op on http://localhost.
  - X-Content-Type-Options: nosniff
  - X-Frame-Options: DENY  (same defense as frame-ancestors below, but
    older browsers only read this one)
  - Referrer-Policy: strict-origin-when-cross-origin
  - Permissions-Policy: deny camera/mic/geolocation/payment/usb. We
    don't use any of those APIs; closing them off prevents a supply-
    chain compromise or a forgotten plugin from silently enabling them.

Report-only:
  - Content-Security-Policy-Report-Only with a pragmatic allowlist:
      default-src 'self'
      script-src  'self' 'unsafe-inline' 'unsafe-eval'
      style-src   'self' 'unsafe-inline'
      img-src     'self' data: blob: https:
      font-src    'self' data:
      connect-src 'self' https://*.supabase.co wss://*.supabase.co
      frame-ancestors 'none'
      base-uri    'self'
      form-action 'self'
    'unsafe-inline' / 'unsafe-eval' are there because Next's inline
    hydration script + dev-mode require them; nonce-based CSP is a
    later project. Violations appear in the browser console but
    nothing is blocked until we flip the header name to
    `Content-Security-Policy`.

Verified against the running dev server:
  - /, /docs, /login, /api/whatsapp/webhook, /_next/static/* all
    return the six headers.
  - No CSP violations on / or /docs in the browser console.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 19:24:41 +03:00
Arnas Donauskas
56c76af739
fix(deploy): Cache-Control headers so CDN stops serving stale HTML
Root cause: Hostinger's CDN was applying s-maxage=31536000 (1 year)
to prerendered HTML pages by default. Each deploy produced fresh
Turbopack chunk hashes, but the edge kept serving year-old HTML that
referenced chunk filenames the new build no longer had on disk —
resulting in HTML 200 + every /_next/static/*.{js,css} 404, page
rendered unstyled. Private/incognito didn't help because the cache
is at the edge, not the browser.

Fix: explicit Cache-Control via next.config.ts headers():
- /_next/static/*  — public, max-age=31536000, immutable
  Content-hashed filenames; safe forever.
- /api/*           — no-store
  Per-user, must never be shared at the edge.
- everything else  — public, max-age=0, s-maxage=300,
                     stale-while-revalidate=86400
  Edge serves instantly from cache for 5 min, then keeps serving
  cached content while refreshing in the background for up to 24h.
  Chunk-hash drift after a deploy self-heals within ~5 min.

Verification after deploy:
  curl -I https://<host>/login | grep -i cache-control
  Expect: public, max-age=0, s-maxage=300, stale-while-revalidate=86400
  (If Hostinger overwrites this, fall back to configuring
  purge-on-deploy at the platform layer.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:34:46 +03:00
Arnas Donauskas
c70bfe0139
Initial commit from Create Next App 2026-04-16 17:52:39 +03:00