Audit-Pruefung: "manipuliert" von "Luecke" getrennt + Retention fuer Routine-Auth
Problem 1 (Deutbarkeit): verifyIntegrity warf zwei voellig unterschiedliche Befunde in einen Topf und meldete beides als "N manipulierte Eintraege". Eine harmlose Verkettungsluecke sah damit aus wie ein Angriff - die Meldung war im Alltag nicht deutbar und dadurch wertlos, dasselbe Muster wie beim Refresh-Rauschen. Fix: Rueckgabe um tamperedEntries (Inhalt nachtraeglich veraendert, ernst) und chainGaps (Verkettung unterbrochen durch parallele Schreibvorgaenge oder geloeschte Zeilen, meist harmlos) erweitert. invalidEntries bleibt als Summe erhalten. Controller formuliert die Meldung eindeutig, Frontend-API-Typ nachgezogen. Problem 2 (Aufbewahrung): Token-Refreshes landen seit der Entrauschung als Authentication/LOW. Diese Kombination traf auf keine spezifische Regel und fiel in die Auffangregel * mit 3650 Tagen - das Rauschen waere 10 Jahre aufbewahrt worden, echte Logins nur 2. Fix: Regel Authentication/LOW mit 90 Tagen, als idempotente Migration und im Seed. Sensitivitaet steuert die Aufbewahrung und ist keine Alarmstufe - normale Logins und Zugriffe auf Bankdaten/Ausweise bleiben bewusst CRITICAL, ein Herabstufen wuerde still die Aufbewahrungsfrist verlaengern. Verifiziert: Live-Test gegen Dev-DB - echte Manipulation einer Zeile wird als manipuliert erkannt und nicht mit Luecken verwechselt, Ketten-Luecken bleiben bei 7, Originalzustand exakt wiederhergestellt. tsc + vite build gruen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -450,7 +450,20 @@ export async function getAuditLogsByDataSubject(customerId: number) {
|
||||
export async function verifyIntegrity(fromId?: number, toId?: number): Promise<{
|
||||
valid: boolean;
|
||||
checkedCount: number;
|
||||
/** Alle beanstandeten Zeilen (tampered + chainGaps) – Abwaertskompatibilitaet. */
|
||||
invalidEntries: number[];
|
||||
/**
|
||||
* ERNST: Der Inhalt der Zeile passt nicht mehr zu ihrem Hash – jemand hat
|
||||
* einen bestehenden Eintrag nachtraeglich veraendert.
|
||||
*/
|
||||
tamperedEntries: number[];
|
||||
/**
|
||||
* MEIST HARMLOS: Der Inhalt stimmt, aber die Verkettung zur Vorgaengerzeile
|
||||
* passt nicht. Ursachen: parallel geschriebene Eintraege (bis zum Fix der
|
||||
* Race-Condition) oder geloeschte Zeilen (Retention-Cleanup). Kein Hinweis
|
||||
* auf Manipulation – die Zeilen selbst sind unveraendert.
|
||||
*/
|
||||
chainGaps: number[];
|
||||
}> {
|
||||
const where: Prisma.AuditLogWhereInput = {};
|
||||
|
||||
@@ -473,7 +486,8 @@ export async function verifyIntegrity(fromId?: number, toId?: number): Promise<{
|
||||
},
|
||||
});
|
||||
|
||||
const invalidEntries: number[] = [];
|
||||
const tamperedEntries: number[] = [];
|
||||
const chainGaps: number[] = [];
|
||||
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
const log = logs[i];
|
||||
@@ -503,7 +517,7 @@ export async function verifyIntegrity(fromId?: number, toId?: number): Promise<{
|
||||
previousHash: log.previousHash,
|
||||
});
|
||||
if (log.hash !== legacyHash) {
|
||||
invalidEntries.push(log.id);
|
||||
tamperedEntries.push(log.id);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -512,15 +526,19 @@ export async function verifyIntegrity(fromId?: number, toId?: number): Promise<{
|
||||
if (i > 0) {
|
||||
const previousLog = logs[i - 1];
|
||||
if (log.previousHash !== previousLog.hash) {
|
||||
invalidEntries.push(log.id);
|
||||
chainGaps.push(log.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const invalidEntries = [...tamperedEntries, ...chainGaps].sort((a, b) => a - b);
|
||||
|
||||
return {
|
||||
valid: invalidEntries.length === 0,
|
||||
checkedCount: logs.length,
|
||||
invalidEntries,
|
||||
tamperedEntries,
|
||||
chainGaps,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user