R191-01: Ein PUT, eine Klammer

Befund der Pentesterin nach dem R190-01-Fix. Nur der Rollentausch lag in
der Transaktion, die drei Haken liefen danach in eigenen Schreibvorgaengen.
Ein Multi-Feld-PUT war damit nicht gesamt-atomar: Bricht ein Haken-Write
ab, steht der Rollenstand schon und die Haken halb. Kein Verlust, keine
Eskalation, aber ein Zwischenstand, den niemand angefordert hat. Ein PUT
ist ein Vorgang, also gehoert er in eine Klammer.

Die gesamte Schreibphase von updateUser liegt jetzt in einer Transaktion -
Benutzerdaten, Rollentausch, alle drei Haken. createUser ebenso.

Beim Umbau mitgefunden: Die drei Haken-Helfer legten die Rolle bei Bedarf
selbst an, falls sie fehlte. Das war eine vierte Stelle, die definierte,
was "Developer" bedeutet - mit einem anderen Rechtesatz als der Katalog
(nur developer:access statt allem) und ohne isSystem. Eine so entstandene
Rolle waere ueber die Rollenverwaltung aenderbar gewesen. Der Notfallpfad
ist weg: sync-roles legt die Rollen bei jedem Start an, die Startwache
meldet ihr Fehlen, und fehlt sie hier doch, bricht der Vorgang mit klarer
Ansage ab. Drei fast gleiche Funktionen wurden dabei eine.

int4-Ueberlauf (kosmetischer Nebenbefund): IDs jenseits des INT-Bereichs
werden nicht mehr abgefragt, sondern als unbekannt gemeldet.

createUser hasht jetzt mit Cost 12 statt 10, wie seed.ts. Wieder eine
Haertung, die nur in einer von zwei Kopien angekommen war.

Nachgeprueft: Rollback bewiesen, indem die DSGVO-Rolle voruebergehend
umbenannt und {roleIds:[23], hasGdprAccess:true} geschickt wurde - 400 mit
Klartext, Rollen unveraendert. Typvektoren "22", 4.5, 1e3, true, null,
Riesenzahl alle 400 ohne Wipe. R190-01-Regression erneut gruen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-09 01:40:56 +02:00
co-authored by Claude Opus 5
parent b2963be482
commit 702e630ee5
3 changed files with 204 additions and 239 deletions
+33
View File
@@ -99,6 +99,39 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
- [x] **🔗 R191-01: Ein PUT, eine Klammer** (2026-09-09)
- Befund der Pentesterin nach dem R190-01-Fix: Nur der Rollentausch lag in
der Transaktion, die drei Haken (DSGVO/Developer/Audit-Betrieb) liefen
**danach** in eigenen Schreibvorgängen. Ein Multi-Feld-PUT war damit nicht
gesamt-atomar — bricht ein Haken-Write ab, steht der Rollenstand schon und
die Haken halb. Kein Verlust, keine Eskalation, aber ein Zwischenstand, den
niemand angefordert hat.
- Fix: Die **gesamte** Schreibphase von `updateUser` in einer
`$transaction` — Benutzerdaten, Rollentausch, alle drei Haken.
`createUser` ebenso: Konto und Haken zusammen.
- **Beim Umbau mitgefunden:** Die drei Haken-Helfer **legten die Rolle bei
Bedarf selbst an**, falls sie fehlte. Das war eine *vierte* Stelle, die
definierte, was „Developer" bedeutet — mit einem anderen Rechtesatz als der
Katalog (nur `developer:access` statt allem) und **ohne `isSystem`**. Eine
so entstandene Rolle wäre über die Rollenverwaltung änderbar gewesen. Der
Notfallpfad ist weg: `sync-roles` legt die Rollen bei jedem Start an, die
Startwache meldet ihr Fehlen, und fehlt sie hier doch, bricht der Vorgang
mit klarer Ansage ab statt etwas Ähnliches zu erfinden. Drei fast gleiche
Funktionen wurden dabei eine.
- **int4-Überlauf** (ihr kosmetischer Nebenbefund): IDs jenseits des
INT-Bereichs werden gar nicht mehr abgefragt, sondern als unbekannt
gemeldet — `9999999999` sagt jetzt „Unbekannte Rollen-ID" statt
„Fehler beim Aktualisieren". Gleiche Behandlung für Rechte-IDs.
- **`createUser` hasht jetzt mit Cost 12** statt 10, wie `seed.ts`. Wieder
eine Härtung, die nur in einer von zwei Kopien angekommen war.
- Nachgeprüft: Rollback bewiesen, indem die DSGVO-Rolle vorübergehend
umbenannt und ein `{roleIds:[23], hasGdprAccess:true}` geschickt wurde →
400 mit Klartext, Rollen **unverändert** (kein Teil-Write). Ihre
Typvektoren `"22"`, `4.5`, `1e3`, `true`, `null`, Riesenzahl → alle 400,
kein Wipe. R190-01-Regression erneut grün.
- Dateien: `src/services/user.service.ts`, `src/services/rechte.service.ts`
- [x] **🧨 R190-01: Rollentausch zerstörte, wo er ablehnte** (2026-09-09)
- Befund der Pentesterin: `updateUser` machte `deleteMany` + `createMany`
**ohne Transaktion und ohne `skipDuplicates`**. Eine doppelte roleId