Entfernter Protokoll-Anfang wurde nicht erkannt

Gefunden bei der Vorbereitung des Prod-Siegels. Die Verkettung wird
zeilenweise gegen die Vorgaengerin geprueft - die erste Zeile hat keine,
also fiel bisher nichts auf, wenn ein zusammenhaengender Anfang des
Protokolls entfernt wurde. Kein Kettenbruch, kein Befund, valid blieb
gruen. Das ist die stillste Loeschung von allen: Wer die aeltesten
Eintraege loswerden will, muss nur vorne anfangen.

Erkennbar ist es trotzdem. Die allererste Zeile wird ohne Vorgaenger
geschrieben und traegt einen leeren previousHash; traegt die erste
VORHANDENE Zeile einen Wert, hat es eine Vorgaengerin gegeben und die ist
weg. Wird jetzt als Kettenluecke an dieser Zeile gefuehrt, mit derselben
Manifest- und Beglaubigungslogik wie jede andere Luecke - eine
dokumentierte Loeschung erklaert sie also weiterhin.

Nur bei Pruefung des Gesamtbereichs: mit fromId ist ein gefuellter
previousHash selbstverstaendlich. Gegengeprueft, kein Fehlalarm.

Getestet ueber HTTP gegen eine Wegwerf-DB: vollstaendiges Protokoll ->
valid:true; erste drei Zeilen entfernt -> vorher unveraendert valid:true,
jetzt valid:false mit chainGaps:[4], wegen Hash-Version 3 zusaetzlich als
Manipulation eskaliert.

Auf Prod ausgeschlossen: Das Protokoll beginnt bei ID 1 (07.05.2026,
Inbetriebnahme), kein Cleanup, keine Neuberechnung.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-26 18:53:13 +02:00
co-authored by Claude Opus 5
parent 2ca6ed2f70
commit eb0580ac54
2 changed files with 50 additions and 0 deletions
+28
View File
@@ -1297,6 +1297,34 @@ export async function verifyIntegrity(fromId?: number, toId?: number): Promise<{
} }
tamperedEntries.push(...backlogTampered, ...backlogMissing); tamperedEntries.push(...backlogTampered, ...backlogMissing);
// ---------------------------------------------------------------------
// Fehlender ANFANG des Protokolls.
//
// Die Verkettung wird zeilenweise gegen die Vorgaengerin geprueft - die
// erste Zeile hat keine, also fiel bisher NICHTS auf, wenn ein
// zusammenhaengender Anfang entfernt wurde. Kein Kettenbruch, kein Befund,
// `valid` blieb gruen. Das ist die stillste Loeschung von allen: Wer die
// aeltesten Eintraege loswerden will, muss nur vorne anfangen.
//
// Erkennbar ist es trotzdem: Die allererste Zeile eines Protokolls wird ohne
// Vorgaenger geschrieben und traegt deshalb einen leeren `previousHash`.
// Traegt die erste vorhandene Zeile einen Wert, hat es eine Vorgaengerin
// gegeben - und die ist weg.
//
// Nur bei Pruefung des GESAMTEN Bereichs; bei `fromId` ist ein gefuellter
// `previousHash` selbstverstaendlich und kein Befund.
if (fromId === undefined && logs.length > 0 && logs[0].previousHash) {
chainGaps.push(logs[0].id);
// Ein protokolliertes Loeschungs-Manifest erklaert auch diese Luecke; die
// Pruefung laeuft ueber denselben Weg wie bei jeder anderen.
if (!gapErklaert(0, logs[0].id)) {
unexplainedGaps.push(logs[0].id);
if (erwarteteVersion(logs[0].id) === 3) {
tamperedEntries.push(logs[0].id);
}
}
}
for (let i = 0; i < logs.length; i++) { for (let i = 0; i < logs.length; i++) {
const log = logs[i]; const log = logs[i];
+22
View File
@@ -97,6 +97,28 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
## ✅ Erledigt ## ✅ Erledigt
- [x] **🕳️ Entfernter Protokoll-ANFANG wurde nicht erkannt** (2026-08-26)
- Gefunden bei der Vorbereitung des Prod-Siegels: Die Verkettung wird
zeilenweise gegen die Vorgängerin geprüft die **erste** Zeile hat keine,
also fiel bisher **nichts** auf, wenn ein zusammenhängender Anfang des
Protokolls entfernt wurde. Kein Kettenbruch, kein Befund, `valid` blieb
grün. Die stillste Löschung von allen: Wer die ältesten Einträge loswerden
will, muss nur vorne anfangen.
- Erkennbar ist es trotzdem: Die allererste Zeile wird ohne Vorgänger
geschrieben und trägt einen leeren `previousHash`. Trägt die erste
**vorhandene** Zeile einen Wert, hat es eine Vorgängerin gegeben und die
ist weg. Wird jetzt als Kettenlücke an dieser Zeile geführt, mit derselben
Manifest- und Beglaubigungslogik wie jede andere Lücke.
- Nur bei Prüfung des Gesamtbereichs; mit `fromId` ist ein gefüllter
`previousHash` selbstverständlich (gegengeprüft, kein Fehlalarm).
- Getestet über HTTP: vollständiges Protokoll → `valid:true`; erste drei
Zeilen entfernt → **vorher** unverändert `valid:true`, **jetzt**
`valid:false`, `chainGaps:[4]`, wegen Hash-Version 3 zusätzlich als
Manipulation eskaliert.
- Auf Prod ausgeschlossen: Das Protokoll beginnt bei ID 1 (07.05.2026,
Inbetriebnahme), kein Cleanup, keine Neuberechnung.
- Datei: `backend/src/services/audit.service.ts`
- [x] **⏱️ Neuberechnung der Kette ist jetzt eine eigene Gegenbuch-Alarmbedingung (Pentest R186, Frage b)** (2026-08-26) - [x] **⏱️ Neuberechnung der Kette ist jetzt eine eigene Gegenbuch-Alarmbedingung (Pentest R186, Frage b)** (2026-08-26)
- Der Tester fragte präzise: Löst `cleanup``rehash` **ohne** erneutes - Der Tester fragte präzise: Löst `cleanup``rehash` **ohne** erneutes
Siegeln, über **nicht versiegelten** Inhalt, etwas **Automatisches** aus Siegeln, über **nicht versiegelten** Inhalt, etwas **Automatisches** aus