198 lines
6.2 KiB
Markdown
198 lines
6.2 KiB
Markdown
|
|
STEP 11a – AUDIT-LOG INTEGRITAET (HASH-KETTE)
|
|||
|
|
Datum: 2026-02-22
|
|||
|
|
Status: ABGESCHLOSSEN
|
|||
|
|
|
|||
|
|
=====================================================================
|
|||
|
|
1. ZIEL
|
|||
|
|
=====================================================================
|
|||
|
|
|
|||
|
|
Audit-Log (aza_audit_log.py) manipulations-erkennbar machen
|
|||
|
|
durch SHA-256-Hash-Kette, analog zum Consent-Log.
|
|||
|
|
|
|||
|
|
=====================================================================
|
|||
|
|
2. AENDERUNGEN
|
|||
|
|
=====================================================================
|
|||
|
|
|
|||
|
|
Datei: aza_audit_log.py
|
|||
|
|
|
|||
|
|
a) Neues Format (8 Felder statt 6):
|
|||
|
|
TIMESTAMP | EVENT | USER | STATUS | SOURCE | DETAIL | PREV_HASH | ENTRY_HASH
|
|||
|
|
|
|||
|
|
b) Hash-Berechnung:
|
|||
|
|
entry_hash = SHA-256(prev_hash + payload)
|
|||
|
|
payload = "TS | EVENT | USER | STATUS | SOURCE | DETAIL"
|
|||
|
|
Startwert (GENESIS): 64x "0"
|
|||
|
|
|
|||
|
|
c) Rotation mit Ketten-Uebergabe:
|
|||
|
|
Bei Rotation wird der letzte Hash des rotierten Files
|
|||
|
|
als Header in der neuen Datei gespeichert:
|
|||
|
|
#CHAIN_FROM=<letzter_entry_hash>
|
|||
|
|
Neue Eintraege setzen prev_hash = Chain-Header-Hash.
|
|||
|
|
Ein Auditor kann die Kette ueber Dateigrenzen pruefen.
|
|||
|
|
|
|||
|
|
d) Neue Funktionen:
|
|||
|
|
- verify_integrity(path) -> (bool, list[str])
|
|||
|
|
Prueft eine einzelne Logdatei auf Ketten-Integritaet.
|
|||
|
|
- verify_all_rotations() -> (bool, dict)
|
|||
|
|
Prueft alle rotierten Dateien.
|
|||
|
|
|
|||
|
|
e) CLI-Interface:
|
|||
|
|
python -m aza_audit_log verify -> Aktuelle Datei pruefen
|
|||
|
|
python -m aza_audit_log verify --all -> Alle Rotationsdateien
|
|||
|
|
python -m aza_audit_log verify --file X -> Bestimmte Datei
|
|||
|
|
python -m aza_audit_log stats -> Statistiken + Integritaet
|
|||
|
|
python -m aza_audit_log export -> JSON-Export mit Integritaet
|
|||
|
|
|
|||
|
|
f) Export enthaelt jetzt:
|
|||
|
|
- integrity: PASS/FAIL
|
|||
|
|
- integrity_errors: []
|
|||
|
|
- Jeder Entry hat prev_hash und entry_hash
|
|||
|
|
|
|||
|
|
g) get_log_stats() enthaelt jetzt:
|
|||
|
|
- integrity: PASS/FAIL
|
|||
|
|
|
|||
|
|
=====================================================================
|
|||
|
|
3. ROTATIONS-STRATEGIE
|
|||
|
|
=====================================================================
|
|||
|
|
|
|||
|
|
Ablauf bei Rotation (Datei > AZA_AUDIT_ROTATE_MB):
|
|||
|
|
|
|||
|
|
1. Letzten entry_hash der aktuellen Datei auslesen
|
|||
|
|
2. Bestehende .1, .2, ... Dateien hochschieben
|
|||
|
|
3. Aktuelle Datei -> .1 verschieben
|
|||
|
|
4. Neue leere Datei anlegen mit Header:
|
|||
|
|
#CHAIN_FROM=<letzter_hash>
|
|||
|
|
5. Neue Eintraege nutzen diesen Hash als prev_hash
|
|||
|
|
|
|||
|
|
Verifizierung:
|
|||
|
|
- verify_integrity() pro Datei: prueft interne Kette
|
|||
|
|
- Header #CHAIN_FROM verbindet die Dateien logisch
|
|||
|
|
- verify_all_rotations() prueft alle Dateien der Reihe nach
|
|||
|
|
|
|||
|
|
=====================================================================
|
|||
|
|
4. BEISPIEL LOG-ZEILE
|
|||
|
|
=====================================================================
|
|||
|
|
|
|||
|
|
2026-02-22T21:42:27.160+00:00 | APP_START | user_1 | OK | desktop | test | 000000...0000 | a3f8e1...
|
|||
|
|
|
|||
|
|
Felder:
|
|||
|
|
[0] Timestamp (UTC, ISO-8601)
|
|||
|
|
[1] Event-Typ
|
|||
|
|
[2] User-ID
|
|||
|
|
[3] Status (OK/FAIL)
|
|||
|
|
[4] Source
|
|||
|
|
[5] Detail (max 200 Zeichen, keine sensiblen Daten)
|
|||
|
|
[6] prev_hash (SHA-256 des vorherigen Eintrags)
|
|||
|
|
[7] entry_hash (SHA-256 ueber prev_hash + Felder 0-5)
|
|||
|
|
|
|||
|
|
=====================================================================
|
|||
|
|
5. VERIFY-ANLEITUNG + BEISPIELAUSGABEN
|
|||
|
|
=====================================================================
|
|||
|
|
|
|||
|
|
a) Integritaet pruefen (CLI):
|
|||
|
|
|
|||
|
|
$ python -m aza_audit_log verify
|
|||
|
|
Datei: C:\...\aza_audit.log
|
|||
|
|
Integritaet: PASS
|
|||
|
|
|
|||
|
|
b) Manipulation erkennen:
|
|||
|
|
|
|||
|
|
$ python -m aza_audit_log verify
|
|||
|
|
Datei: C:\...\aza_audit.log
|
|||
|
|
Integritaet: FAIL
|
|||
|
|
Zeile 2: entry_hash stimmt nicht (erwartet 104ebe9a..., gefunden 32e00f09...)
|
|||
|
|
|
|||
|
|
c) Alle Rotationsdateien:
|
|||
|
|
|
|||
|
|
$ python -m aza_audit_log verify --all
|
|||
|
|
aza_audit.1.log: PASS
|
|||
|
|
aza_audit.log: PASS
|
|||
|
|
GESAMT: PASS
|
|||
|
|
|
|||
|
|
d) Statistiken:
|
|||
|
|
|
|||
|
|
$ python -m aza_audit_log stats
|
|||
|
|
Datei: aza_audit.log
|
|||
|
|
Existiert: True
|
|||
|
|
Groesse: 0.0 MB
|
|||
|
|
Eintraege: 2
|
|||
|
|
Integritaet: PASS
|
|||
|
|
|
|||
|
|
=====================================================================
|
|||
|
|
6. TEST-ERGEBNIS (PROOF)
|
|||
|
|
=====================================================================
|
|||
|
|
|
|||
|
|
Testskript: _test_audit_integrity.py
|
|||
|
|
21 Tests, 0 Fehler.
|
|||
|
|
|
|||
|
|
Tests:
|
|||
|
|
1. Hash-Kette schreiben + verifizieren:
|
|||
|
|
- 5 Eintraege geschrieben, verify PASS
|
|||
|
|
- 8 Felder pro Zeile
|
|||
|
|
- prev_hash[0] = GENESIS
|
|||
|
|
- prev_hash[n] = entry_hash[n-1]
|
|||
|
|
|
|||
|
|
2. Manipulation erkennen:
|
|||
|
|
- 1 Zeichen geaendert (LOGIN_OK -> LOGIN_XX)
|
|||
|
|
- verify -> FAIL, Fehlerstelle gemeldet
|
|||
|
|
- Restore -> PASS
|
|||
|
|
|
|||
|
|
3. Rotation mit Ketten-Uebergabe:
|
|||
|
|
- Rotierte Datei (.1) intakt: PASS
|
|||
|
|
- Aktuelle Datei mit Chain-Header: PASS
|
|||
|
|
- Header-Hash == letzter Hash der rotierten Datei: PASS
|
|||
|
|
- prev_hash im neuen File == Chain-Header: PASS
|
|||
|
|
- verify_all_rotations: PASS
|
|||
|
|
|
|||
|
|
4. Stats + Export:
|
|||
|
|
- Integritaet in Stats: PASS
|
|||
|
|
- Export integrity: PASS
|
|||
|
|
- Entries mit entry_hash: PASS
|
|||
|
|
|
|||
|
|
5. Data Minimization:
|
|||
|
|
- Kein Passwort, kein API-Key, kein Transkript: PASS
|
|||
|
|
|
|||
|
|
=====================================================================
|
|||
|
|
7. DATA MINIMIZATION
|
|||
|
|
=====================================================================
|
|||
|
|
|
|||
|
|
Unveraendert gegenueber STEP 11:
|
|||
|
|
- Keine Patientennamen
|
|||
|
|
- Keine Transkripte/Prompts
|
|||
|
|
- Keine Passwoerter/API-Keys
|
|||
|
|
- Detail max. 200 Zeichen, nur Metadaten
|
|||
|
|
|
|||
|
|
=====================================================================
|
|||
|
|
8. BETROFFENE DATEIEN
|
|||
|
|
=====================================================================
|
|||
|
|
|
|||
|
|
Geaendert:
|
|||
|
|
- aza_audit_log.py (Format erweitert, Hash-Kette, verify, CLI)
|
|||
|
|
|
|||
|
|
Neu:
|
|||
|
|
- _test_audit_integrity.py (Proof-Skript)
|
|||
|
|
- security/handovers/STEP_11a_AUDIT_LOG_INTEGRITY.md (dieses Dokument)
|
|||
|
|
|
|||
|
|
Nicht geaendert:
|
|||
|
|
- basis14.py (Aufrufe bleiben kompatibel, neue Felder transparent)
|
|||
|
|
- aza_settings_mixin.py (unveraendert)
|
|||
|
|
- aza_consent.py (unveraendert)
|
|||
|
|
|
|||
|
|
=====================================================================
|
|||
|
|
9. RISIKEN
|
|||
|
|
=====================================================================
|
|||
|
|
|
|||
|
|
- Performance: _get_last_hash() liest die gesamte Datei.
|
|||
|
|
Bei sehr grossen Dateien (kurz vor Rotation) kann dies langsam sein.
|
|||
|
|
Akzeptabel, da Rotation bei 10 MB greift.
|
|||
|
|
|
|||
|
|
- Rueckwaertskompatibilitaet: Bestehende 6-Feld-Logdateien werden
|
|||
|
|
von verify_integrity() als ungueltig gemeldet (< 8 Felder).
|
|||
|
|
Loesung: Bestehende Logdatei vor erstem Start archivieren/loeschen.
|
|||
|
|
|
|||
|
|
=====================================================================
|
|||
|
|
10. OFFENE PUNKTE
|
|||
|
|
=====================================================================
|
|||
|
|
|
|||
|
|
Keine.
|