[EPIC] Public-Readiness II: HTTP-/User-API härten (Endpoint-Scope-Audit, Auth/Session, Dependency-Scan, Secrets) #186

Closed
opened 2026-06-26 12:23:47 +00:00 by chinux · 4 comments
Owner

Ziel

Zweite Flanke fuer Public: die oeffentliche HTTP-/User-API absichern (Browser-/User-Seite), parallel zum Agent-Kanal (#184). Auth-Flows, Endpoint-Scope, Dependencies, Secrets, Frontend.

Hintergrund

#184 haertet den Agent→Backend-Pfad. Sobald das Backend public ist, ist aber auch die User-API extern erreichbar — eine eigene Angriffsflaeche. Der #108-Cluster hat gezeigt, dass "Endpoint ohne Scope-Check" hier real vorkam.

Arbeitspakete

Endpoint-Scope-Audit (systematisch)

  • Alle 22 Router durchgehen: jeder Endpoint, der node-/vm-/tenant-bezogene Daten liefert/aendert, MUSS require_read/require_role + check_node_scope/list_user_accessible_nodes haben (Muster aus #108). Checkliste pro Router, kein Endpoint ungeprueft.
  • IDOR-Check: UUID/ID-Parameter ohne Ownership-Pruefung finden.

Auth-/Session-Haertung

  • JWT-Handling: Ablauf (access/refresh TTL), Signatur-Algo (kein none), Rotation/Revocation.
  • mustchange/Passwort-Flows, Brute-Force-Schutz am Login (analog #181 fuer User-Login).
  • CORS-Policy fuer public (keine Wildcard mit Credentials), Security-Header (HSTS, X-Frame-Options, CSP-Basis).

Dependency-Scanning (in CI scharf)

  • Python (pip-audit), Rust (cargo audit), npm (npm audit) als CI-Jobs — zunaechst report, dann blockierend bei HIGH/CRITICAL. Knuepft an #55 (CI-Gates noch continue-on-error).

Secrets-/Deployment-Hygiene

  • #93 (GUAC_SECRET + 12 ENV-Vars in .env.example) abschliessen — Fail-Fast-Onboarding.
  • Keine Default-Passwoerter/Secrets in compose (GUAC_SECRET-Default ...change-me raus).
  • DB/interne Services nie im public compose exponiert.

Frontend

  • #119 abschliessen (DOMPurify an allen {@html}, Timer-Leaks, svelte-check).
  • CSRF-Betrachtung fuer state-aendernde Requests.

Definition of Done

  • Jeder daten-/aktionsfuehrende API-Endpoint ist auth- + scope-gepft (kein Cross-Tenant/IDOR).
  • Login/Session gegen Brute-Force + Token-Missbrauch gehaertet; public-taugliche CORS/Header.
  • Dependency-Scans laufen in CI (HIGH/CRIT blockierend).
  • Keine Default-Secrets; .env.example vollstaendig (#93); DB nicht public.
  • Frontend-XSS-Restpunkte (#119) zu.

Bezug

Schwester-Epic zu #184. Enthaelt/ko ordiniert #93, #119, #55 (CI-Gates), #95 (Service-Extraktion erleichtert das Scope-Audit + Tests).

## Ziel Zweite Flanke fuer Public: die **oeffentliche HTTP-/User-API** absichern (Browser-/User-Seite), parallel zum Agent-Kanal (#184). Auth-Flows, Endpoint-Scope, Dependencies, Secrets, Frontend. ## Hintergrund #184 haertet den **Agent→Backend**-Pfad. Sobald das Backend public ist, ist aber auch die **User-API** extern erreichbar — eine eigene Angriffsflaeche. Der #108-Cluster hat gezeigt, dass "Endpoint ohne Scope-Check" hier real vorkam. ## Arbeitspakete **Endpoint-Scope-Audit (systematisch)** - [ ] Alle 22 Router durchgehen: jeder Endpoint, der node-/vm-/tenant-bezogene Daten liefert/aendert, MUSS `require_read`/`require_role` + `check_node_scope`/`list_user_accessible_nodes` haben (Muster aus #108). Checkliste pro Router, kein Endpoint ungeprueft. - [ ] IDOR-Check: UUID/ID-Parameter ohne Ownership-Pruefung finden. **Auth-/Session-Haertung** - [ ] JWT-Handling: Ablauf (access/refresh TTL), Signatur-Algo (kein `none`), Rotation/Revocation. - [ ] mustchange/Passwort-Flows, Brute-Force-Schutz am Login (analog #181 fuer User-Login). - [ ] CORS-Policy fuer public (keine Wildcard mit Credentials), Security-Header (HSTS, X-Frame-Options, CSP-Basis). **Dependency-Scanning (in CI scharf)** - [ ] Python (pip-audit), Rust (cargo audit), npm (npm audit) als CI-Jobs — zunaechst report, dann blockierend bei HIGH/CRITICAL. Knuepft an #55 (CI-Gates noch continue-on-error). **Secrets-/Deployment-Hygiene** - [ ] #93 (GUAC_SECRET + 12 ENV-Vars in .env.example) abschliessen — Fail-Fast-Onboarding. - [ ] Keine Default-Passwoerter/Secrets in compose (GUAC_SECRET-Default `...change-me` raus). - [ ] DB/interne Services nie im public compose exponiert. **Frontend** - [ ] #119 abschliessen (DOMPurify an allen {@html}, Timer-Leaks, svelte-check). - [ ] CSRF-Betrachtung fuer state-aendernde Requests. ## Definition of Done - Jeder daten-/aktionsfuehrende API-Endpoint ist auth- + scope-gepft (kein Cross-Tenant/IDOR). - Login/Session gegen Brute-Force + Token-Missbrauch gehaertet; public-taugliche CORS/Header. - Dependency-Scans laufen in CI (HIGH/CRIT blockierend). - Keine Default-Secrets; .env.example vollstaendig (#93); DB nicht public. - Frontend-XSS-Restpunkte (#119) zu. ## Bezug Schwester-Epic zu #184. Enthaelt/ko ordiniert #93, #119, #55 (CI-Gates), #95 (Service-Extraktion erleichtert das Scope-Audit + Tests).
Author
Owner

Arbeitspaket 1/5 — Endpoint-Scope-Audit · Commit bc816e7

Systematischer Durchgang aller 24 Router (~270 Endpoints) via 6 parallele Read-only-Audit-Agents, Muster aus #108. Report im Wiki: Security-Endpoint-Audit.md.

16 Findings gefunden + behoben:

HIGH (cross-tenant Mutation / IDOR)

  • schedule_router /jobs-Cluster (6 Endpoints): list/create/get/patch/delete/run waren ungescoped → POST /jobs/{id}/run fuehrte fremde Jobs auf fremden Nodes aus. Jetzt require_read+Filter / check_node_scope / check_vm_scope / _scope_job.
  • update_router POST /bulk-job: Operator konnte Updates auf fremden Tenant-VMs ausloesen → check_vm_scope je entry. +/bulk-job/{id} & cancel-item IDOR → _assert_job_in_scope.

MEDIUM

  • docker compose-update/status: IDOR via geratenem cmd_id (cross-VM Live-Log) → an node/vmid gebunden.
  • security /scan-history + /scan-state, admin /cluster/overview, audit /stats: cross-tenant Daten/Counts → tenant-gescoped.
  • template POST/PUT/DELETE: jeder authed User (inkl. viewer) schrieb globale Templates → require_role(operator) + UUID-Guard.

LOW

  • backup /sync-history: viewer triggerte Agent-Arbeit → require_role(operator).

Saubere Router (keine Findings): deploy, net, monitor, rdp, notification, auto_update, auth, faq, temperature, docgen, command, tunnel, me, task, log.

IDOR-Check mit erledigt: alle UUID/ID-Parameter ohne Ownership-Pruefung sind die obigen Findings; require_superadmin-Endpoints laden per ID ohne Check, aber SA ueberspringt Scope (kein IDOR).

⚠️ Aktivierung: reine Backend-Auth-Verschaerfung, wirksam erst nach Backend-Rebuild — gekoppelt mit dem #185-Deploy (Migration 0024 + Re-Enrollment), daher hier noch nicht gebaut.

Offene Pakete (Epic bleibt offen)

  • Auth-/Session-Haertung (Login-Bruteforce analog #181, JWT-TTL/Algo/Revocation, CORS/Header)
  • Dependency-Scanning CI (pip/cargo/npm audit, #55)
  • Secrets-Hygiene (#93 .env.example, GUAC_SECRET-Default raus, DB nicht public)
  • Frontend #119 (DOMPurify, Timer-Leaks, svelte-check), CSRF-Betrachtung

Sag, welches Paket als naechstes.

## Arbeitspaket 1/5 — Endpoint-Scope-Audit ✅ · Commit `bc816e7` Systematischer Durchgang **aller 24 Router** (~270 Endpoints) via 6 parallele Read-only-Audit-Agents, Muster aus #108. Report im Wiki: [Security-Endpoint-Audit.md](https://git.itdata-gera.de/chinux/theProx/src/branch/main/wiki/Security-Endpoint-Audit.md). **16 Findings gefunden + behoben:** *HIGH (cross-tenant Mutation / IDOR)* - `schedule_router` /jobs-Cluster (6 Endpoints): list/create/get/patch/delete/run waren ungescoped → `POST /jobs/{id}/run` fuehrte fremde Jobs auf fremden Nodes aus. Jetzt require_read+Filter / check_node_scope / check_vm_scope / _scope_job. - `update_router POST /bulk-job`: Operator konnte Updates auf fremden Tenant-VMs ausloesen → check_vm_scope je entry. +/bulk-job/{id} & cancel-item IDOR → _assert_job_in_scope. *MEDIUM* - `docker compose-update/status`: IDOR via geratenem cmd_id (cross-VM Live-Log) → an node/vmid gebunden. - `security /scan-history` + /scan-state, `admin /cluster/overview`, `audit /stats`: cross-tenant Daten/Counts → tenant-gescoped. - `template POST/PUT/DELETE`: jeder authed User (inkl. viewer) schrieb globale Templates → require_role(operator) + UUID-Guard. *LOW* - `backup /sync-history`: viewer triggerte Agent-Arbeit → require_role(operator). **Saubere Router (keine Findings):** deploy, net, monitor, rdp, notification, auto_update, auth, faq, temperature, docgen, command, tunnel, me, task, log. **IDOR-Check** mit erledigt: alle UUID/ID-Parameter ohne Ownership-Pruefung sind die obigen Findings; require_superadmin-Endpoints laden per ID ohne Check, aber SA ueberspringt Scope (kein IDOR). ⚠️ **Aktivierung**: reine Backend-Auth-Verschaerfung, wirksam erst nach Backend-Rebuild — gekoppelt mit dem #185-Deploy (Migration 0024 + Re-Enrollment), daher hier noch nicht gebaut. ### Offene Pakete (Epic bleibt offen) - [ ] Auth-/Session-Haertung (Login-Bruteforce analog #181, JWT-TTL/Algo/Revocation, CORS/Header) - [ ] Dependency-Scanning CI (pip/cargo/npm audit, #55) - [ ] Secrets-Hygiene (#93 .env.example, GUAC_SECRET-Default raus, DB nicht public) - [ ] Frontend #119 (DOMPurify, Timer-Leaks, svelte-check), CSRF-Betrachtung Sag, welches Paket als naechstes.
Author
Owner

Paket 1/5 (Endpoint-Scope-Audit) verifiziert @ bc816e7 — korrekt umgesetzt.

HIGH einzeln gegen Code geprüft:

  • schedule_router: _scope_job deckt GET/PATCH/DELETE/run + List/Create (kein Start fremder Jobs auf fremden Nodes mehr) ✓
  • update_router /bulk-job POST: check_vm_scope je entry (Operator kann keine fremden Tenant-VMs mehr einreihen); GET + cancel-item via _assert_job_in_scope (404 statt 403 → kein Cross-Tenant-Orakel) ✓; alle per-VM-Endpoints (scan/update/preview/repair) mit check_vm_scope

MEDIUM-Stichproben:

  • template POST/PUT/DELETE: require_role("operator") ergänzt (Rolegate fehlte) ✓
  • admin /cluster/overview: aggregiert nur noch _scoped_nodes_for_bulk statt alle ✓

Report wiki/Security-Endpoint-Audit.md vorhanden, 15 Router sauber. Backend-Auth-Verschärfung → wirksam erst nach Rebuild, mit #185-Deploy gekoppelt (Migration 0024 + Re-Enroll, siehe Deployment-Public.md Abschnitt 7).

Epic bleibt offen — 4 Pakete übrig: Auth/Session-Härtung (Login-Brute-Force + JWT) · Dependency-Scan-CI (#55) · Secrets (#93) · Frontend (#119).

**Paket 1/5 (Endpoint-Scope-Audit) verifiziert @ bc816e7 — korrekt umgesetzt.** HIGH einzeln gegen Code geprüft: - `schedule_router`: `_scope_job` deckt GET/PATCH/DELETE/**run** + List/Create (kein Start fremder Jobs auf fremden Nodes mehr) ✓ - `update_router /bulk-job` POST: **`check_vm_scope` je entry** (Operator kann keine fremden Tenant-VMs mehr einreihen); GET + cancel-item via `_assert_job_in_scope` (404 statt 403 → kein Cross-Tenant-Orakel) ✓; alle per-VM-Endpoints (scan/update/preview/repair) mit `check_vm_scope` ✓ MEDIUM-Stichproben: - `template` POST/PUT/DELETE: `require_role("operator")` ergänzt (Rolegate fehlte) ✓ - `admin /cluster/overview`: aggregiert nur noch `_scoped_nodes_for_bulk` statt alle ✓ Report `wiki/Security-Endpoint-Audit.md` vorhanden, 15 Router sauber. Backend-Auth-Verschärfung → **wirksam erst nach Rebuild, mit #185-Deploy gekoppelt** (Migration 0024 + Re-Enroll, siehe Deployment-Public.md Abschnitt 7). **Epic bleibt offen — 4 Pakete übrig:** Auth/Session-Härtung (Login-Brute-Force + JWT) · Dependency-Scan-CI (#55) · Secrets (#93) · Frontend (#119).
Author
Owner

Pakete A–D abgeschlossen (Endpoint-Scope-Audit/Paket 1 war `bc816e7`). Epic bleibt offen.

Paket Commit Status
A — Secrets-/Deploy-Hygiene (#93) `ec599a1`
B — Token-Revocation/Refresh-Rotation `edb3f7d`
C — Dependency-Scanning CI (#55) `9973377`
D — Frontend-Härtung (#119) `38e0530`

Paket B (die einzige echte Auth-Lücke): serverseitige Token-Invalidierung. Denylist-Tabelle `revoked_tokens` + Migration 0025 + globaler Cutoff `users.tokens_revoked_at`. Logout denylistet Access+Refresh-jti; `/refresh` rotiert (rotating refresh tokens); Reuse eines rotierten Refresh-jti → komplette Session-Kette gesperrt + `auth.refresh.reuse`-Log; neuer `DELETE /auth/logout-all`; abgelaufene Denylist-Einträge werden bei `/refresh` aufgeräumt. Live smoke-getestet: logout→401, rotation→neues Paar, reuse→401+chain-lock.

⚠️ Deploy: Paket B braucht `alembic upgrade head` (Migration 0025) beim Backend-Rebuild — passt mit dem #185-Deploy (ohnehin Rebuild) zusammen.

Bereits vorhanden (nicht angefasst): Login-Rate-Limit, JWT-Algo-Pinning, JWT-TTL, 2FA, Agent-Kanal #184.

Pakete A–D abgeschlossen (Endpoint-Scope-Audit/Paket 1 war \`bc816e7\`). Epic bleibt offen. | Paket | Commit | Status | |---|---|---| | A — Secrets-/Deploy-Hygiene (#93) | \`ec599a1\` | ✅ | | B — Token-Revocation/Refresh-Rotation | \`edb3f7d\` | ✅ | | C — Dependency-Scanning CI (#55) | \`9973377\` | ✅ | | D — Frontend-Härtung (#119) | \`38e0530\` | ✅ | **Paket B** (die einzige echte Auth-Lücke): serverseitige Token-Invalidierung. Denylist-Tabelle \`revoked_tokens\` + Migration **0025** + globaler Cutoff \`users.tokens_revoked_at\`. Logout denylistet Access+Refresh-jti; \`/refresh\` rotiert (rotating refresh tokens); Reuse eines rotierten Refresh-jti → komplette Session-Kette gesperrt + \`auth.refresh.reuse\`-Log; neuer \`DELETE /auth/logout-all\`; abgelaufene Denylist-Einträge werden bei \`/refresh\` aufgeräumt. Live smoke-getestet: logout→401, rotation→neues Paar, reuse→401+chain-lock. ⚠️ **Deploy:** Paket B braucht \`alembic upgrade head\` (Migration 0025) beim Backend-Rebuild — passt mit dem #185-Deploy (ohnehin Rebuild) zusammen. Bereits vorhanden (nicht angefasst): Login-Rate-Limit, JWT-Algo-Pinning, JWT-TTL, 2FA, Agent-Kanal #184.
Author
Owner

Epic abgeschlossen — alle 5 Pakete verifiziert @ 38e0530

  • Paket 1 Endpoint-Scope-Audit (bc816e7) — 16 Cross-Tenant/IDOR-Fixes, HIGH einzeln gegen Code geprüft.
  • A Secrets/Deploy (#93, ec599a1) — GUAC_SECRET-Schwach-Default raus (${GUAC_SECRET:?…}), .env.example vollständig.
  • B Token-Revocation (edb3f7d) — RevokedToken + Migration 0025; Revocation wird in get_current_user bei JEDEM Request geprüft (assert_token_valid, rbac.py:70 — der Make-or-break); Logout revoked, Refresh-Rotation, Reuse-Detection mit Chain-Lock (revoke_all_user_tokens), tokens_revoked_at-Cutoff, Housekeeping. Live getestet (logout→401, rotation, reuse→401+chain-lock).
  • C Dependency-Scan-CI (#55, 9973377) — pip/cargo/npm-audit (Report+Gate), gitleaks blockierend.
  • D Frontend (#119, 38e0530) — alle 4 {@html} bereits sanitisiert, Timer gepaart, svelte-check 0 Fehler.
  • CORS (bereits vorhanden) — Wildcard fail-closed abgelehnt (allow_credentials=True), explizite Allow-List Pflicht.

Migrations-Kette: 1 Head (0025), konsistent. Backend-Auth-Verschärfungen wirksam nach Rebuild (mit #185-Deploy gekoppelt, Migration 0025).

Beide Public-Readiness-Flanken stehen damit: #184 (Agent-Kanal) + #186 (HTTP-API).

Offene Design-Entscheidung (kein Blocker): Lint-Gates (fmt/clippy/ruff/svelte-check) bleiben bewusst auf report — bei Public-Readiness korrekt, da nur Security-Gates (audit+gitleaks) scharf sein müssen. Lint blockierend erst nach einem dedizierten Lint-Cleanup (sonst sofort rot durch Bestands-Lint-Debt).

## Epic abgeschlossen ✅ — alle 5 Pakete verifiziert @ 38e0530 - ✅ **Paket 1** Endpoint-Scope-Audit (bc816e7) — 16 Cross-Tenant/IDOR-Fixes, HIGH einzeln gegen Code geprüft. - ✅ **A** Secrets/Deploy (#93, ec599a1) — GUAC_SECRET-Schwach-Default raus (`${GUAC_SECRET:?…}`), .env.example vollständig. - ✅ **B** Token-Revocation (edb3f7d) — `RevokedToken` + Migration 0025; **Revocation wird in `get_current_user` bei JEDEM Request geprüft** (`assert_token_valid`, rbac.py:70 — der Make-or-break); Logout revoked, Refresh-Rotation, **Reuse-Detection mit Chain-Lock** (`revoke_all_user_tokens`), `tokens_revoked_at`-Cutoff, Housekeeping. Live getestet (logout→401, rotation, reuse→401+chain-lock). - ✅ **C** Dependency-Scan-CI (#55, 9973377) — pip/cargo/npm-audit (Report+Gate), gitleaks blockierend. - ✅ **D** Frontend (#119, 38e0530) — alle 4 {@html} bereits sanitisiert, Timer gepaart, svelte-check 0 Fehler. - ✅ **CORS** (bereits vorhanden) — Wildcard fail-closed abgelehnt (allow_credentials=True), explizite Allow-List Pflicht. Migrations-Kette: 1 Head (0025), konsistent. Backend-Auth-Verschärfungen wirksam nach Rebuild (mit #185-Deploy gekoppelt, Migration 0025). **Beide Public-Readiness-Flanken stehen damit: #184 (Agent-Kanal) + #186 (HTTP-API).** Offene Design-Entscheidung (kein Blocker): Lint-Gates (fmt/clippy/ruff/svelte-check) bleiben bewusst auf `report` — bei Public-Readiness korrekt, da nur Security-Gates (audit+gitleaks) scharf sein müssen. Lint blockierend erst nach einem dedizierten Lint-Cleanup (sonst sofort rot durch Bestands-Lint-Debt).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
chinux/theProx#186
No description provided.