dorfteich/docs/architecture/security.md
Claude Fable 5 0629411966 Add architecture documentation, ADRs, and operations concept
Initial deliverable of the architecture phase: 16 ADRs (stack, CRDT
collaboration, plugin sandbox, import/export, backups, CI/CD), data
model, permission model, real-time collaboration and plugin concepts,
deployment/operations/security documentation, and the milestone roadmap
that the implementation issues are derived from.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 14:36:16 +02:00

4.5 KiB

Security concept

Threat-driven summary; detailed mechanics live in the referenced ADRs.

Assets & main threats

Wiki content (possibly confidential per pond/label), user credentials and e-mail addresses, instance availability. Threat actors: anonymous internet (public instance with self-signup), malicious registered users, malicious or sloppy plugin authors, compromised dependencies.

Authentication & session security (ADR 0007)

  • Argon2id password hashing; opaque server-side sessions in HttpOnly, Secure, SameSite=Lax cookies; CSRF protected by SameSite + origin checks on mutating requests (double-submit token for the file-download edge cases).
  • E-mail verification (double opt-in) before an account can create content; password reset via single-use hashed tokens; both rate-limited.
  • Rate limiting (DB-backed) on login, signup, reset, and API; lockout backoff on repeated failed logins per account+IP.
  • Self-registration can be disabled instance-wide; personal-pond quotas (editors/readers/ponds/storage) bound the blast radius of spam accounts.

Authorization

  • Single resolution algorithm (permissions.md) in packages/shared, enforced in API guards and at collab token issuance — never in the client.
  • Default-closed: no grant → no access. Public access is always an explicit grant.
  • Admin actions are audit-logged (operations.md).

Content & upload security

  • Editor content is structured (ProseMirror schema) — no raw HTML from users. The HTML render endpoint escapes everything outside the schema; link protocols allowlisted (https, http, mailto).
  • Uploads (ADR 0011): MIME/extension allowlist, size limits, magic-byte checks, SVG sanitization or rejection, Content-Disposition: attachment for non-image types, no user content served same-origin as executable (X-Content-Type-Options: nosniff; uploads path never serves text/html).
  • App CSP (strict): default-src 'self'; font-src 'self' (ADR 0016); no third-party origins at all — the GDPR posture is "zero external requests".

Plugin sandboxing (ADR 0008, operational)

  • Code plugins: opaque-origin iframes, no network (connect-src 'none'), capability-scoped postMessage API executed with the viewer's permissions server-side; declared capabilities surfaced to the Site Admin at install time.
  • Style plugins: CSS sanitized (no @import/external url()), scoped class names.
  • Install surface restricted to Site Admins; packages size-limited and schema-validated; the plugins/ directory watcher only trusts the volume (host-level access implies game over anyway).

Collaboration layer

  • WebSocket connect requires a short-lived (≤ 60 s) single-purpose JWT bound to user + page + mode; write revocation closes sessions via LISTEN/NOTIFY (realtime-collaboration.md).
  • Update size and document size ceilings prevent resource-exhaustion via crafted CRDT updates.

Secrets & configuration

  • Secrets (DB password, collab signing key, SMTP credentials) live only in the stage .env (mode 600, never in git) and container env — not in the database (instance_settings stores non-secret config; the SMTP password entered in the setup wizard is written to the env-backed secret store, not to a DB row).
  • Key rotation: collab signing key and session pepper rotate via env change
    • rolling restart; procedure documented in operations.md runbooks.
  • Dependencies: lockfile-pinned; monthly update batch; images pinned to digests in Prod.

Privacy (GDPR)

  • No external requests from the browser (fonts self-hosted, no CDNs, no analytics by default).
  • Instance-configurable legal pages (imprint, privacy policy) are a core feature; dorfteich.online uses the operator's standard texts.
  • Data minimization: username, e-mail, password hash, locale — nothing else required. Account deletion: personal pond and authored ponds follow the trash/purge path; authorship on shared content is pseudonymized ("deleted user"). A data-export endpoint (own profile + own ponds as Markdown/ZIP) supports access/portability requests.
  • IP addresses appear only in rate-limit counters (short TTL) and reverse proxy logs (host-level rotation) — documented in the privacy-policy template.

Out of scope (v1, explicit)

  • No end-to-end encryption of page content (server sees plaintext — needed for search, export, rendering).
  • No plugin marketplace/signing — installation is a deliberate Site Admin act of trust in the reviewed package.
  • No SSO in MVP (OIDC-ready per ADR 0007).