From 343545b59e6b2955a868bd2444d2f02a3bd900df Mon Sep 17 00:00:00 2001 From: Bernd Steckmeister Date: Sat, 4 Jul 2026 13:51:32 +0200 Subject: [PATCH] security: server.py multithreaded + Diag-Log-Lock (Review-Befund p, Threading-Haertung vollendet) Co-Authored-By: Claude Fable 5 --- CHANGES.md | 9 +++++++++ PROGRESS.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ROADMAP.md | 3 +++ 3 files changed, 64 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index f848e50..e3077a6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1251,3 +1251,12 @@ 2026-07-04 09:16 [Edit] /home/steggi/pyramid/ROADMAP.md 2026-07-04 09:17 [Edit] /home/steggi/pyramid/PROGRESS.md 2026-07-04 09:17 [Edit] /home/steggi/pyramid/PROGRESS.md +2026-07-04 09:18 [Edit] /home/steggi/.claude-pyramid/projects/-home-steggi-pyramid/memory/pyramid-arbeitsstand.md +2026-07-04 09:43 [Edit] /home/steggi/matrix/server.py +2026-07-04 09:43 [Edit] /home/steggi/matrix/server.py +2026-07-04 09:43 [Edit] /home/steggi/matrix/server.py +2026-07-04 13:46 [Edit] /home/steggi/matrix/server.py +2026-07-04 13:46 [Edit] /home/steggi/matrix/server.py +2026-07-04 13:50 [Edit] /home/steggi/pyramid/PROGRESS.md +2026-07-04 13:51 [Edit] /home/steggi/pyramid/PROGRESS.md +2026-07-04 13:51 [Edit] /home/steggi/pyramid/ROADMAP.md diff --git a/PROGRESS.md b/PROGRESS.md index 1fb733a..0fb1306 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -13,6 +13,45 @@ Schritt (und beim Abbruch mitten im Schritt den Zwischenstand). Format: --- +## 2026-07-04 – Fable-5-Review (p): Interims-Gate geprüft (korrekt) + halbfertige Threading-Härtung einer abgebrochenen Session vollendet + +**Erledigt:** Review-Pass über die jüngste erledigte Arbeit (Interims-Gate, +Commits e97a748/455742d) als Punkt (p) im Fable-5-Review-Abschnitt abgehakt. +Das Gate selbst ist korrekt (Socket-IP als belastbare Prüfung, Cf-Header nur +Zweitschranke, Deny-Log gedeckelt, kein Angreifer-Text im Log). Dabei über das +CHANGES.md-Hook-Log entdeckt: Eine Session hat um 09:43 (NACH dem letzten +Commit) **drei unprotokollierte server.py-Edits** gemacht und wurde mitten in +einer Threading-Härtung abgebrochen – `threading`-Import + `DIAG_LOCK` waren da, +aber der Lock wurde **nirgends benutzt**, und die eigentliche Umstellung auf +`ThreadingHTTPServer` fehlte (der Kommentar behauptete sie schon). Obendrein +lief der Dienst noch mit dem Code von 09:14 – nichts davon war je geladen. +Die angefangene Härtung ist fachlich richtig (der single-threaded `HTTPServer` +ließ EINEN langsamen Client den ganzen Server blockieren – inkl. des öffentlich +erreichbaren `/api/livekit-token`), darum vollendet statt zurückgebaut: +`ThreadingHTTPServer` in `__main__`, Diagnose-Log-Kappen+Anhängen in den +`DIAG_LOCK` gewickelt (einziger öffentlich beschreibbarer Pfad), `timeout = 30` +der Vorsession belassen. Dienst-Neustart (kill/`Restart=always`), headless +verifiziert (11 Prüfungen): stats 200; Admin-Route localhost UND 192.168.178.71 +→ 400 „Kein Nutzer angegeben"; öffentlich UND gespoofter Cf-Header → 403; +livekit-token ungültig → 401; Diagnose falscher Token 403, gültig 200 + im Log, +300 KB → 413; **Slow-Loris-Test: parallele Anfrage in 10 ms beantwortet, +während ein Client hing** (vorher unmöglich), hängender Body-Read nach exakt +~30 s serverseitig beendet, Dienst danach gesund. Test-Einträge aus beiden +Logs wieder entfernt. + +**Offen/Nächster Schritt:** Unverändert – alle offenen ROADMAP-Punkte brauchen +PC/Gerät (SQLCipher, LiveKit-Client-Umstellung, Härtetest) oder Bernd +(Secret-Rotation, Dashboard-Fernzugriff A/B, Call-Pilot-Go). + +**Stolperfallen:** (1) Das CHANGES.md-Hook-Log ist der zuverlässigste Detektor +für unprotokollierte Arbeit abgebrochener Sessions – Zeitstempel der letzten +Einträge mit dem letzten Commit vergleichen. (2) „Datei geändert" heißt NICHT +„läuft": Dienststart-Zeit (`systemctl status`) gegen Datei-mtime prüfen – hier +lagen 30 Minuten Code unausgeführt auf der Platte. (3) Ein definierter, aber +nie benutzter Lock ist ein Halbfertig-Marker, kein Schutz. + +--- + ## 2026-07-04 – Dashboard-Befund (o): akutes Loch mit aussperr-sicherem Interims-Gate geschlossen **Erledigt:** Der KRITISCHE Befund (o) (Dashboard-Admin-Endpoints ohne Auth, @@ -632,6 +671,19 @@ schließt den Review ab. einem aussperr-sicheren Interims-Gate geschlossen (Admin-Routen nur noch Heimnetz/localhost, siehe PROGRESS-Eintrag „Dashboard-Befund (o)" oben) – offen bleibt nur noch die Fernzugriffs-Entscheidung A/B. +- [x] **(p) Interims-Gate (e97a748/455742d) reviewt – korrekt; dabei halbfertige, + unprotokollierte Threading-Härtung einer abgebrochenen Session gefunden und + vollendet (2026-07-04).** Gate-Logik bestätigt: Socket-IP ist die belastbare + Prüfung (nicht spoofbar), Cf-Header nur Zweitschranke, Deny-Log mit 5-MB-Deckel + und ohne attacker-kontrollierten Text; Restrisiken (LAN-CSRF, offene + Nutzerlisten-Ansicht) waren bereits in `docs/DASHBOARD_AUTH_HARDENING.md` + dokumentiert – kein neuer Befund am Gate. ABER: CHANGES-Hook zeigte drei + server.py-Edits um 09:43 ohne Commit/Protokoll – abgebrochene Session hatte + `DIAG_LOCK` definiert, aber nie benutzt, und `ThreadingHTTPServer` im Kommentar + behauptet, aber nicht umgestellt; der Dienst lief zudem noch mit altem Code. + Vollendet (Threading + Lock-Nutzung), Dienst neu gestartet, 11 Headless- + Prüfungen grün inkl. Slow-Loris (parallele Anfrage 10 ms statt blockiert; + hängender Body-Read nach 30 s gekappt). Details im PROGRESS-Eintrag „(p)" oben. **Fazit:** Die Sonnet-5-Arbeit war handwerklich sauber; die zwei echten Lücken (verlorene Kommentare, fehlender Soft-Logout-Guard) hatte die abgebrochene diff --git a/ROADMAP.md b/ROADMAP.md index e9c8099..7dc9bc4 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -71,6 +71,9 @@ Punkte abhaken (`[x]`), wenn erledigt UND in `PROGRESS.md` protokolliert. Admin-Buttons auch von unterwegs? Dann Weg A (Cloudflare Access, empfohlen – schließt auch die weiterhin öffentliche Nutzerlisten-Ansicht) oder Weg B (`DASH_TOKEN`), Plan + Restrisiken in `docs/DASHBOARD_AUTH_HARDENING.md`. + Zusatz (Fable-5-Review (p), 2026-07-04): `server.py` läuft jetzt multithreaded + mit 30-s-Socket-Timeout – ein einzelner langsamer Client kann den Server + (und damit `/api/livekit-token`) nicht mehr blockieren; headless verifiziert. - [x] **LiveKit-Token-Route server-seitig gebaut + verifiziert** (Fable-5-Review (n), PROGRESS.md 2026-07-04). `POST /api/livekit-token` läuft live in `server.py` (whoami-Auth, stdlib-HS256-Minting aus `livekit.yaml`), headless geprüft