Files
fotospiel-app/docs/process/todo/security-review-dec-2025.md
2025-12-09 20:29:32 +01:00

16 KiB

Security Review (Dec 2025)

Goal

Run a structured security review across marketing frontend + public API, Guest PWA, and Event Admin to produce prioritized findings, PoCs, and remediation tasks aligned with the Security Hardening epic.

Deliverables

  • Threat model + scope notes.
  • Findings list with severity/likelihood, PoCs, and recommended fixes.
  • Follow-up tasks filed in docs/process/todo/ or Issues (label TODO) mapped to existing SEC-* tickets where possible.

Status (Stand 2025-12-08)

  • Discovery: In progress (scope mapped; marketing/API route inventory captured).
  • Code review: Not started.
  • Dynamic testing: Not started.
  • Reporting: Not started.

Scope & Trust Boundaries

  • Marketing site + public API (web + api route groups, CORS, rate limits).
  • Guest PWA (resources/js/guest, service worker, background sync, offline cache, uploads).
  • Event Admin / Tenant Admin PWA (Filament resources, React admin, OAuth2/PKCE, Sanctum).
  • Payments/Webhooks (Paddle, RevenueCat), media pipeline (uploads/QR/PDF), storage visibility.
  • Headers/CSP/cookies, session/config defaults, logging hygiene (no PII).

Workstreams & Checklists

  1. Foundations & Threat Model
  • Map roles/data:
    • Marketing visitors (no auth; optional contact form PII).
    • Guest attendees via join token (photos, likes, push subscriptions, optional contact/email if provided).
    • Tenant collaborators/admins (event config, uploads, member lists, notifications).
    • Super admins (platform-level controls).
    • Automated actors (Paddle/RevenueCat webhooks, background workers/queues).
  • Data classes & storage/retention (baseline):
    • Photos/media: stored in configured filesystem disks (see filesystems.php/storage pipeline), variants via signed URLs; retention governed by tenant settings (per PRP 09/10).
    • Join tokens & gallery access: tokens (hashing planned), events, and access logs; rate-limit counters; short-lived signed share links.
    • Account/auth: Sanctum tokens, OAuth (Google), session cookies (same_site=lax, secure flag env-driven), PATs; device/browser not fingerprinted by default.
    • PII/contact: marketing contact form submissions (controller TBD), tenant member lists, notification preferences, billing contact details.
    • Billing: Paddle/Stripe/PayPal identifiers, checkout sessions, add-on purchases; webhooks queued.
    • Logs/metrics: structured logs (no PII mandate in PRP 09), Matomo analytics (consent-gated plan), request timing middleware.
  • Confirm env/header defaults for review:
    • .env.example ships with APP_DEBUG=true and APP_URL=http://localhost; production must set APP_DEBUG=false and HTTPS URL.
    • Session defaults: driver redis (unless overridden), SESSION_ENCRYPT=false, SAME_SITE=lax, SESSION_SECURE_COOKIE unset (inherits HTTPS), partitioned cookies disabled.
    • CORS: default Laravel config (not customized) => paths=['api/*','sanctum/csrf-cookie'], allowed_origins=['*'], allowed_methods=['*'], credentials false.
    • CSP: web group appends ContentSecurityPolicy middleware; in debug/local it skips header. In prod it sets nonce-based script-src and broad style-src 'unsafe-inline' https: data:; allows Stripe/Paddle/Localize, Matomo origin if configured.
  • Test identities / fixtures (seeded):
    • Super admin: ADMIN_EMAIL/ADMIN_PASSWORD (defaults admin@example.com / ChangeMe123!) via SuperAdminSeeder.
    • Tenant admin demo: tenant-demo@fotospiel.app / Demo1234! via DemoTenantSeeder (package assigned, verified, active).
    • Guest tokens: DemoEventSeeder seeds demo-wedding-2025 with join token W2E3sbt7yclzpkAwNSARHYTVN1sPLBad8hfUjLVHmjkUviPd (stored hashed+encrypted). Use for guest/PWA/API tests; additional demo event without explicit token uses generated token.
    • Seed commands: php artisan migrate --seed (or targeted seeders: db:seed --class=SuperAdminSeeder, DemoTenantSeeder, DemoEventSeeder).
  • Env assumptions for dynamic testing:
    • Base URL/HTTPS: ensure APP_URL points to the test host with HTTPS; set SESSION_SECURE_COOKIE=true and SESSION_SAME_SITE=lax/none as needed for cross-origin tools.
    • CORS/stateful domains: configure SANCTUM_STATEFUL_DOMAINS to include test origins (e.g., localhost:3000/5173) for SPA/PWA flows; consider tightening CORS from * to allowed hosts during tests if feasible.
    • Storage: confirm disks (local/s3) and public assets linkage (storage:link) for media tests; signed URL generation in place.
    • Webhooks: set Paddle/RevenueCat webhook secrets and target URLs; use throttling expectations (throttle:60,1 on revenuecat; none on paddle webhooks).
    • Queues: ensure queue workers running for uploads/scan jobs when exercising media pipelines.

Role → Data/Storage/Retention Mapping (initial)

  • Marketing visitor: contact form PII (controller storage TBD); cookies/localStorage for locale/consent; Matomo analytics (consent-gated); no persistent account.
  • Guest (join token): event/gallery access via token; uploads (photo + EXIF), likes, push subscription keys; cached assets in PWA/service worker; signed share links; rate-limit counters and join-token access logs; retention tied to event/gallery expiry and tenant settings.
  • Tenant collaborator/admin: account profile, tenant settings, events, members, notifications, tasks, uploads; billing identifiers for purchases; OAuth/Google tokens; Sanctum PATs/session cookies; audit/logs for actions; retention per tenant policy, legal retention for billing.
  • Super admin: same as tenant admin plus platform-level audit/actions; impersonation logs expected; no extra PII beyond account.
  • Webhooks (Paddle/RevenueCat): payload identifiers, signatures, session linkage; stored in webhook logs/queue jobs; retention per ops runbook.

Dynamic Testing Harness Outline (draft)

  • Identities: use seeded super admin, tenant demo, and demo guest token for auth contexts; create additional tenant collaborator if needed.
  • Environments: run against local HTTPS host with APP_URL set; configure SANCTUM_STATEFUL_DOMAINS and cookies for Playwright/DAST sessions; ensure queues running.
  • Surfaces to script:
    • Marketing/API: contact form abuse/rate limit, coupon preview, gift voucher flows; check CORS preflight and CSP headers.
    • Guest PWA: join token gallery load, photo upload (valid/invalid), like/share, push subscription register/delete, offline/cache poison checks; download/share signed URL enforcement.
    • Event Admin: login (email/password + Google), CRUD on events/photos/members/tasks, package purchase intents (non-payment), photobooth enable/rotate; policy/IDOR checks.
    • Webhooks: replay signed webhook samples (Paddle/RevenueCat) with stale timestamps to validate signature freshness and idempotency behavior.
    • Media pipeline: upload with EXIF/malware test samples to observe AV/EXIF handling; verify signed URL visibility and expiry.

Dynamic Testing Checklists (actionable)

  • Marketing/API

    • Verify CSP headers present in non-debug env; confirm nonce on scripts, no stray inline scripts/styles; note 'unsafe-inline' styles as risk.
    • Exercise contact form with/without JS; confirm throttling and spam validation; inspect error leakage.
    • Coupon preview/gift voucher endpoints: validate rate limits, auth bypass attempts, input validation, CORS preflight, and response caching headers.
    • Checkout wizard/login/register endpoints: session handling, CSRF, rate limits; ensure APP_DEBUG off to avoid stack traces.
    • Public routes return 404/redirects without leaking internal paths.
  • Guest PWA

    • Gallery load with seeded token: check caching headers, ETag, and denial for invalid/expired token.
    • Upload tests: valid image, oversized, wrong MIME, EXIF-laden, EICAR sample; expect AV/EXIF handling and clear errors.
    • Likes/share: ensure signed share links required; verify signed asset URLs enforce expiry and token scope.
    • Push subscription register/delete flows with bad payloads; ensure CORS/preflight and auth tied to token.
    • Service worker/cache: verify scope, versioning, offline fallback, and resistance to cache poisoning (stale manifest/assets).
  • Event Admin

    • Login (email/password) and Google OAuth flow happy/failure paths; session fixation/regeneration checks.
    • CRUD events/photos/members/tasks with tenant slug mismatch to probe IDOR; verify tenant.isolation + policies.
    • Package purchase/payment-intent endpoints without completing payment—check idempotency/validation.
    • Photobooth enable/rotate/disable endpoints with/without admin role.
    • API rate limiting (throttle:tenant-api) and error shape consistency; check storage visibility toggles.
  • Webhooks & Billing

    • Replay Paddle/RevenueCat payloads with valid and stale timestamps; confirm signature verification and replay protection.
    • Send duplicate IDs to test idempotency locks and queueing behavior; observe logs without PII leakage.
    • Ensure webhook routes respect expected throttles (RevenueCat 60/min; Paddle currently none—note risk).
  • Media Pipeline & Storage

    • Signed URL expiry for gallery/download/share links; attempts outside tenant/token should fail.
    • Verify private visibility defaults on new uploads and derivatives; public bucket exposure check.
    • AV/EXIF queue path fires on upload; monitor job logs for failures.
    • Replace public URLs: gallery assets and branding/blog banners now use signed routes; tenant photo resource uses signed URLs for variants.
  • Cross-cutting

    • Headers: HSTS, X-Frame-Options/Frame-Ancestors, Referrer-Policy, Permissions-Policy; note gaps.
    • CSRF on web forms and SPA flows; session cookie flags (Secure/HttpOnly/SameSite) over HTTPS.
    • Rate limits alignment with documented policies; error messages avoid stack traces and sensitive data.

CSP Tightening Plan

  • Add style nonces everywhere inline styles exist (root blade/templates) and remove style-src 'unsafe-inline' outside dev.
  • Ensure script nonce is applied (already set via Vite); audit any inline event handlers.
  • Add frame-ancestors 'self' to CSP to align with X-Frame-Options.

Guest Upload Gating Plan (scan-before-publish, auto-approve; optional moderation)

  • Goals: keep guest uploads pending until AV/EXIF scan completes; auto-approve if clean; optional moderation toggle for tenants that want manual review; serve assets via signed URLs/private storage after approval.
  • Storage/visibility:
    • Store uploads on private disk (no public Storage::url); serve via signed URLs scoped to event/token with short TTL.
    • Keep status=pending until scan completes; do not expose paths in API responses until approved.
  • Security scanning:
    • Dispatch ProcessPhotoSecurityScan on upload; mark security_scan_status and security_scanned_at.
    • If infected/error: mark rejected with reason; optionally delete/quarantine asset and log.
  • Approval workflow:
    • Default: auto-approve when scan returns clean. Optional tenant/event flag photo_upload_requires_manual_approval to hold after scan for manual review (default off).
    • Pending uploads can surface in admin (list + bulk approve/reject) only when manual flag is on.
  • API changes:
    • Guest upload response: return pending state and no direct file URLs while pending.
    • Gallery/photos endpoints: filter to approved only; include pending count for admin if manual flag is on.
    • Signed URL generation: use Storage::temporaryUrl or signed route; avoid raw public paths.
  • Rate/abuse controls:
    • Preserve per-token/device limits; consider stricter throttles while approval is enabled.
    • Log join-token usage and anomalies for audit.
  • Migration/rollout:
    • Backfill existing photos to approved to avoid breaking live galleries.
    • Feature flag to enable per-tenant/event; add config toggle and admin UI.
  • Testing:
    • Feature tests for pending upload, approval flow, rejection, and signed URL access control; scan failure path blocks approval.
  • Trust boundaries/entrypoints:
    • Marketing/Inertia under /{locale} prefix (de|en) with session/Accept-Language fallback redirect; login/register guarded by guest middleware; contact forms throttled (throttle:contact-form); gift voucher print uses signed.
    • Guest PWA entry at /event, /g/{token}, /e/{token}/{path?}, /share/{slug} (views rendered by guest blade; tokens unauthed).
    • Event Admin shell under /event-admin/* with Google OAuth endpoints; auth enforced in controller; SPA catch-all /{view?}.
    • Checkout endpoints always exposed (/purchase-wizard/{package}, /checkout/{package}, /checkout/* helpers, /paddle/webhook); Paddle webhook lacks explicit throttle middleware.
    • API entry at /api/v1 (see details below); testing-only routes gated by env check.
  1. Marketing Frontend + Public API
  • Inventory routes/middleware (auth, rate limits, CORS, cache/ETag) and note anonymous vs authenticated paths:
    • Marketing web routes: locale-prefixed group; auth pages gated by guest; contact/kontakt POST throttled; gift voucher print signed; profile/voucher-status require auth; marketing fallbacks render Inertia 404. Legacy unprefixed routes redirect to locale-prefixed equivalents.
    • Event Admin: /event-admin routes include auth/login/logout/dashboard and SPA catch-all; rely on controller auth checks (middleware not on route).
    • Guest PWA: view routes for gallery/event/share are unauthenticated; token patterns unconstrained except share slug regex.
    • Checkout: purchase-wizard/checkout routes toggled by config('checkout.enabled'); login/register/track-abandoned POSTs exposed; Paddle webhook route has no rate limit middleware.
    • Public API: api/v1 marketing coupon/gift voucher endpoints throttled (throttle:*), RevenueCat webhook throttled 60,1. Public event/gallery endpoints grouped under throttle:100,1; signed URLs for share assets/downloads; uploads exposed at /events/{token}/upload and /photobooth/sparkbooth/upload.
    • Tenant API: auth:sanctum, tenant.collaborator, tenant.isolation, throttle:tenant-api on /api/v1/tenant/*; many routes further gated by tenant.admin; package/credit checks on event mutations; signed download/layout routes within tenant scope.
  • Review controllers/resources for authz (policies/gates), FormRequest validation, mass assignment, IDOR risks.
  • Check response handling (error leakage, pagination limits, idempotency on mutations).
  • Review CSP/headers/cookies and analytics gating; verify no unsafe-inline without nonce/hash plan.
  1. Guest PWA
  • Verify join token handling (hashing/migration alignment with SEC-GT-*), gallery/photo rate limits, throttling per token/IP.
  • Inspect upload validation (MIME/size/dimensions), background sync request signing, storage visibility.
  • Audit service worker scope, cache versioning/poisoning risk, offline fallbacks, and CSP for PWA.
  1. Event Admin (Filament + React Admin)
  • Audit Filament resources/actions for policy checks, scoping, mass assignment guards.
  • Confirm OAuth2/PKCE + Sanctum session handling, role checks, impersonation/tenant boundary controls.
  • Review file handling inside admin (imports/exports/PDF/QR) for SSRF/path traversal.
  1. Payments & Webhooks
  • Validate Paddle/RevenueCat webhook signature verification, timestamp/replay defense, idempotency locks, queueing.
  • Check linkage between webhooks and checkout/session state; ensure failures alert and redact PII.
  1. Media Pipeline & Storage
  • Confirm AV/EXIF scanning coverage, checksum verification, and private visibility defaults.
  • Review signed URL usage/expiry, path traversal protections, and storage bucket separation per tenant.
  1. Dynamic Testing
  • Set up test identities (guest token, tenant admin, super admin) and auth contexts for tooling.
  • Run targeted DAST/Playwright flows for each surface (authn/z, uploads, rate limiting, CORS preflight).
  • Fuzz uploads (images/metadata) and verify rejection paths + logging.

Evidence & Logging

  • Log session notes and findings in docs/process/changes/YYYY-MM-DD-security-review-*.md.
  • Update checklist statuses here after each pass.
  • Open issues for remediation items, linking back to findings and relevant SEC-* tickets.