Audit-Haerten: Fork, Feldabdeckung, Refresh-Rauschen, Route (Pentest R166)

R166-01 (HIGH): Der GET_LOCK-Ansatz gab die Sperre im finally INNERHALB des
Transaktions-Callbacks frei, also vor dem COMMIT. Im Fenster Release-Commit las
der naechste Schreiber ein noch nicht sichtbares Kettenende - zwei Zeilen hingen
am selben Vorgaenger. Meine vorherige Messung war zu schwach: sie suchte Luecken
zwischen Nachbarn, nicht Forks. Fix: einzeiliger Mutex AuditChainLock mit
FOR UPDATE (InnoDB-Zeilensperren fallen erst beim COMMIT) plus
isolationLevel ReadCommitted. Belegt im Direktvergleich mit geweitetem Fenster:
Release-vor-Commit forkt, Zeilensperre nicht.

R166-02 (MEDIUM): Der Hash deckte nur 7 Felder ab. changesBefore/After, success,
ipAddress, resourceLabel, dataSubjectId, userId/customerId waren ungeschuetzt -
ein Einzeledit dort blieb unsichtbar. Fix: hashVersion + generateHashV2 ueber
alle Inhaltsspalten. Bestandszeilen behalten Version 1 und bleiben ohne Rehash
gueltig. Verifiziert: 5/5 zuvor ungeschuetzte Felder werden jetzt erkannt.

R166-03 (LOW): "kein Cookie" (normaler Erstbesuch) wurde als HIGH/abgelehnt
gefuehrt - jetzt eigener Ausgang mit LOW. Nur echte Ablehnung bleibt HIGH.

R166-04 (LOW, pre-existing): GET /retention-policies wurde von GET /:id
verschluckt. Konkrete Routen jetzt vor der Parameter-Route.

Design-Empfehlungen: runRetentionCleanup schreibt ein Loeschungs-Manifest
(ID-Bereich, Anzahl, Policy, Cutoff) als eigenen verketteten Eintrag - Luecken
ausserhalb bleiben erklaerungsbeduerftig. rehashAll schreibt einen Marker.

Verifiziert: 50 parallele Schreiber -> 50/50, 0 Forks, alle V2, manipuliert 0,
Luecken unveraendert 7. tsc + vite build gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 14:56:10 +02:00
co-authored by Claude Opus 5
parent c7d6b6de7e
commit f2a4baacdb
7 changed files with 431 additions and 108 deletions
@@ -0,0 +1,13 @@
-- Hash-Versionierung fuer Audit-Eintraege (Pentest R166-02).
--
-- Der bisherige Hash deckte nur 7 Felder ab (userEmail, action, resourceType,
-- resourceId, endpoint, createdAt, previousHash). NICHT gehasht waren u. a.
-- changesBefore/changesAfter (die eigentliche Nutzlast), success, ipAddress,
-- resourceLabel, dataSubjectId, userId/customerId - ein nachtraeglicher
-- Einzeledit an genau diesen Feldern blieb also unsichtbar.
--
-- Version 2 hasht alle Inhaltsspalten. Bestandszeilen behalten Version 1 und
-- werden weiterhin mit dem alten Verfahren geprueft - kein Rehash noetig,
-- die Beweiskraft der Vergangenheit bleibt erhalten.
ALTER TABLE `AuditLog`
ADD COLUMN IF NOT EXISTS `hashVersion` INT NOT NULL DEFAULT 1;