Audit-Log¶
Das Audit-Log dokumentiert alle sicherheitsrelevanten Aktionen der App und dient als Nachweis für Datenschutzbeauftragte und Aufsichtsbehörden. Es ist als SHA-256-Hash-Chain implementiert und kann optional mit einem Ed25519-Träger-Signaturschlüssel signiert werden.
Ausführliche Spezifikation inklusive Schlüssel-Setup und Verifikation siehe Audit-Log Signatur.
Was wird protokolliert?¶
Alle Events sind in AuditEvent als Factory-Methoden definiert
(lib/core/storage/audit_log.dart):
| Event | Wann | Details (Auszug) |
|---|---|---|
password_set |
Erststart oder Passwort-Wechsel | — |
login_success |
Erfolgreiche Anmeldung | — |
login_failed |
Fehleingabe | — |
login_locked |
Rate-Limit erreicht | lockSeconds |
signature_created |
Datenschutzerklärung unterzeichnet | userName, policyHash |
report_generated |
Nach erfolgreichem LLM-Aufruf | mappingCount, model, reportType, inputTokens, outputTokens, costUsd |
api_key_validated |
Beim Test eines neuen API-Keys | provider |
data_reset |
Voll-Reset über Einstellungen | protectedBoxes |
dictionary_exported |
Export des Wörterbuchs | entries |
dictionary_imported |
Import des Wörterbuchs | imported |
pseudonymization_run |
Bei jedem Pseudonymizing-Lauf | replacements, warnings |
key_generated |
Neuer Audit-Schlüssel im Setup-Wizard erzeugt | fingerprint |
key_imported |
Bestehender Audit-Schlüssel als PEM importiert | fingerprint |
key_rotated |
Audit-Schlüssel ausgetauscht | oldFingerprint, newFingerprint |
Keine personenbezogenen Daten landen im Audit-Log — nur Zähler, Modell-IDs, Provider-Namen, Fingerprints und Zeitstempel.
Kontextfelder pro Eintrag¶
Seit der Forensik-Erweiterung trägt jeder Eintrag zusätzlich:
| Feld | Quelle | Zweck |
|---|---|---|
userName |
Aus der Datenschutz-Signatur | Wer hat die Aktion ausgeführt |
deviceId |
UUID v4, beim ersten Start persistent erzeugt | Welches Gerät |
appVersion |
package_info_plus (z.B. 0.2.0+2) |
Welcher Build |
hostname |
Platform.localHostname |
Welcher Rechner (bei mehreren Mitarbeitern an mehreren Geräten) |
Die Felder kommen aus AuditContext (siehe lib/core/audit/audit_context.dart)
und werden in AuditLog.log() automatisch in jeden Eintrag eingesetzt.
Eintrags-Format¶
{
"timestamp": "2026-05-22T07:25:13.221Z",
"action": "report_generated",
"details": {
"mappingCount": 18,
"model": "claude-sonnet-4-6",
"reportType": "informationsbericht",
"inputTokens": 2845,
"outputTokens": 1612,
"costUsd": 0.018
},
"userName": "Mirko Richter",
"deviceId": "8f29a3c1-1b4c-4d0a-9d3e-5b6e7f8a9c0d",
"appVersion": "0.2.0+2",
"hostname": "dasi-fachkraft-04",
"prev_hash": "0a1b2c3d…",
"hash": "fedcba98…"
}
Hash-Chain¶
Eintrag 0: prev_hash = GENESIS (64x "0")
hash = SHA-256(canonical_json(payload_0))
Eintrag 1: prev_hash = hash(0)
hash = SHA-256(canonical_json(payload_1))
Eintrag 2: prev_hash = hash(1)
hash = SHA-256(canonical_json(payload_2))
...
canonical_json ist eine deterministische JSON-Serialisierung mit
sortierten Keys. Damit hängt der Hash nur vom Inhalt ab, nicht von der
Reihenfolge der Felder.
Manipulationen erkennen¶
AuditLog.verifyChain() läuft die Kette von vorne nach hinten ab und
prüft pro Eintrag:
prev_hashstimmt mit demhashdes Vorgängers überein?hashist tatsächlich der SHA-256 über den restlichen Inhalt?
Bei Fehlern wird ein Fehlertext zurückgegeben:
| Fehler | Bedeutung |
|---|---|
Eintrag N: prev_hash bricht die Kette |
Ein vorhergehender Eintrag wurde gelöscht oder seine Reihenfolge geändert. |
Eintrag N: Hash stimmt nicht — Manipulation möglich |
Der Inhalt des Eintrags wurde editiert. |
In-App-Viewer¶
Unter Einstellungen → Datenschutz → Audit-Log ansehen** öffnet sich ein Viewer mit:
- Liste aller Einträge (neueste zuerst)
- Filter-Chips nach Event-Typ (Bericht, Login, Pseudonymisierung …)
- Datums-Filter (Heute / 7 Tage / 30 Tage / Alle)
- AppBar-Button „Chain prüfen" — startet
verifyChain()und zeigt grün/rot-Dialog - AppBar-Button „Exportieren" — siehe unten
Export¶
Der Export liefert je nach Konfiguration:
| Status | Format |
|---|---|
| Kein Audit-Schlüssel eingerichtet | Plain-JSON mit Hash-Chain |
| Audit-Schlüssel im Setup-Wizard aktiv | JSON mit Hash-Chain und Ed25519-Detached-Signatur + Public-Key + Fingerprint |
Beispiel (signiert):
{
"appName": "FEGH-Bericht",
"appVersion": "0.2.0+2",
"exportedAt": "2026-05-22T07:25:00.221Z",
"chainValid": true,
"algorithm": "Ed25519",
"publicKeyFingerprint": "5D:3C:2E:1B:7A:8F:90:23",
"publicKey": "MCowBQYDK2VwAyEA…",
"entries": [ /* … */ ],
"signature": "5RZ7gMt…"
}
Der externe Python-Verifier in tools/verify_audit_export.py prüft
Hash-Chain und Signatur und gibt OK/FAIL aus. Aufruf:
pip install cryptography
python verify_audit_export.py audit_export.json [traeger_public.pem]
Was passiert beim data_reset?¶
Das Audit-Log überlebt jeden Factory-Reset absichtlich. Der
DataResetService führt eine ausdrückliche Schutzliste:
| Geschützte Box | Begründung |
|---|---|
audit_log |
Forensischer Nachweis, gesetzlich erforderlich |
audit_context |
Device-ID muss konstant bleiben, sonst Bruch in der Zuordnung |
audit_keys |
Träger-Signaturschlüssel — sonst werden alte Exports unverifizierbar |
Vor dem Reset wird ein data_reset-Event mit protectedBoxes geschrieben,
sodass die Hash-Chain durchgängig bleibt — auch nach dem Reset.
Best-Practice¶
- Audit-Schlüssel beim Setup einrichten — Variante A (per OpenSSL beim DSB) oder Variante B (In-App-Wizard mit PEM-Backup). Details: Audit-Log Signatur.
- Monatlich exportieren und auf einem schreibgeschützten Medium (USB-Stick mit Schreibsperre, Cloud-Bucket mit WORM-Policy) ablegen.
- Stichproben verifizieren — externe Python-CLI nutzen, Hash-Chain und Signatur müssen beide grün sein.
- Bei Verdacht auf Manipulation sofort exportieren, verifizieren, und den DSB informieren.