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:
@@ -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];
|
||||||
|
|
||||||
|
|||||||
@@ -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 –
|
||||||
|
|||||||
Reference in New Issue
Block a user