210 lines
6.2 KiB
Markdown
210 lines
6.2 KiB
Markdown
|
|
# STEP 10a – Consent Audit-Proof (Nachweis + Checkliste)
|
|||
|
|
|
|||
|
|
Datum: 22.02.2026
|
|||
|
|
Pruefung durch: Internes Audit-Skript (_test_consent_audit.py)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. Speicherort + Schema
|
|||
|
|
|
|||
|
|
Datei: aza_consent_log.json (Projekt-Root)
|
|||
|
|
Format: JSON Array (Append-only, kein Ueberschreiben)
|
|||
|
|
|
|||
|
|
Schema pro Eintrag:
|
|||
|
|
|
|||
|
|
Feld Typ Beschreibung
|
|||
|
|
-----------------------------------------------
|
|||
|
|
user_id string Benutzer-ID aus Profil
|
|||
|
|
consent_type string Immer "ai_processing"
|
|||
|
|
consent_version string Stand-Datum aus ai_consent.md
|
|||
|
|
timestamp string UTC ISO-8601
|
|||
|
|
source string "ui" / "test" / "admin"
|
|||
|
|
action string "grant" oder "revoke"
|
|||
|
|
prev_hash string SHA-256 des vorherigen Eintrags
|
|||
|
|
hash string SHA-256 dieses Eintrags
|
|||
|
|
|
|||
|
|
Versions-Mechanismus:
|
|||
|
|
consent_version wird aus legal/ai_consent.md extrahiert.
|
|||
|
|
Die Funktion _get_consent_version() liest die Zeile, die mit
|
|||
|
|
"Stand:" beginnt, und gibt den Wert nach dem Doppelpunkt zurueck.
|
|||
|
|
Aktuell: "Februar 2026"
|
|||
|
|
Bei Aenderung des Datums in ai_consent.md wird jede bestehende
|
|||
|
|
Einwilligung ungueltig und muss erneuert werden.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Beispiel-Logeintraege (sanitized)
|
|||
|
|
|
|||
|
|
2a) GRANT (Zustimmung):
|
|||
|
|
|
|||
|
|
{
|
|||
|
|
"user_id": "user_1",
|
|||
|
|
"consent_type": "ai_processing",
|
|||
|
|
"consent_version": "Februar 2026",
|
|||
|
|
"timestamp": "2026-02-22T21:13:25.419060+00:00",
|
|||
|
|
"source": "ui",
|
|||
|
|
"action": "grant",
|
|||
|
|
"prev_hash": "000000000000000000000000000000000000000000000000...",
|
|||
|
|
"hash": "6988dcc3fb7215af69eb1fcdd35afaf7aab37262b3ed..."
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2b) REVOKE (Widerruf):
|
|||
|
|
|
|||
|
|
{
|
|||
|
|
"user_id": "user_1",
|
|||
|
|
"consent_type": "ai_processing",
|
|||
|
|
"consent_version": "Februar 2026",
|
|||
|
|
"timestamp": "2026-02-22T21:13:25.419060+00:00",
|
|||
|
|
"source": "ui",
|
|||
|
|
"action": "revoke",
|
|||
|
|
"prev_hash": "6988dcc3fb7215af69eb1fcdd35afaf7aab37262b3ed...",
|
|||
|
|
"hash": "2a60ef4a43cefc8e3c39dc155530c0f443bbb0b47b0e..."
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2c) RE-GRANT (erneute Zustimmung):
|
|||
|
|
|
|||
|
|
{
|
|||
|
|
"user_id": "user_1",
|
|||
|
|
"consent_type": "ai_processing",
|
|||
|
|
"consent_version": "Februar 2026",
|
|||
|
|
"timestamp": "2026-02-22T21:13:25.421171+00:00",
|
|||
|
|
"source": "ui",
|
|||
|
|
"action": "grant",
|
|||
|
|
"prev_hash": "2a60ef4a43cefc8e3c39dc155530c0f443bbb0b47b0e...",
|
|||
|
|
"hash": "2cb429a75c3d02f8861c6fd6fbec1216acb6a453926a..."
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Timestamp-Pruefung (UTC-Nachweis):
|
|||
|
|
Alle Timestamps enden auf "+00:00" -> UTC bestaetigt.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Integritaetsbeweis
|
|||
|
|
|
|||
|
|
3a) Intakte Log-Datei:
|
|||
|
|
|
|||
|
|
verify_chain_integrity() -> PASS
|
|||
|
|
Alle Hash-Werte stimmen mit der Berechnung ueberein.
|
|||
|
|
Alle prev_hash-Referenzen sind korrekt verkettet.
|
|||
|
|
|
|||
|
|
3b) Manipulierte Log-Datei:
|
|||
|
|
|
|||
|
|
Manipulation: timestamp von Eintrag 0 um ein Zeichen geaendert
|
|||
|
|
("...+00:00" -> "...+00:0X")
|
|||
|
|
|
|||
|
|
verify_chain_integrity() -> FAIL
|
|||
|
|
Fehlermeldung:
|
|||
|
|
"Eintrag 0: Hash stimmt nicht
|
|||
|
|
(erwartet 8b92439ca6d1b926..., gefunden 6988dcc3fb7215af...)"
|
|||
|
|
|
|||
|
|
Ergebnis: Manipulation wird zuverlaessig erkannt.
|
|||
|
|
|
|||
|
|
3c) Nach Restore der Originaldatei:
|
|||
|
|
|
|||
|
|
verify_chain_integrity() -> PASS
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Enforcement-Beweis
|
|||
|
|
|
|||
|
|
4a) Ohne Consent:
|
|||
|
|
has_valid_consent("user_1") -> False
|
|||
|
|
KI-Funktion: BLOCKIERT
|
|||
|
|
Verhalten: RuntimeError "KI-Einwilligung fehlt oder wurde widerrufen."
|
|||
|
|
UI: Consent-Dialog wird angezeigt (Checkbox + Zustimmen-Button)
|
|||
|
|
|
|||
|
|
4b) Nach Consent:
|
|||
|
|
record_consent("user_1") ausgefuehrt
|
|||
|
|
has_valid_consent("user_1") -> True
|
|||
|
|
KI-Funktion: ERLAUBT
|
|||
|
|
|
|||
|
|
4c) Nach Widerruf:
|
|||
|
|
record_revoke("user_1") ausgefuehrt
|
|||
|
|
has_valid_consent("user_1") -> False
|
|||
|
|
KI-Funktion: BLOCKIERT
|
|||
|
|
|
|||
|
|
4d) Version-Change (consent_version geaendert):
|
|||
|
|
Vor Aenderung: has_valid_consent -> True
|
|||
|
|
consent_version im Log manuell auf "Januar 2025" gesetzt
|
|||
|
|
Aktuelle Version in ai_consent.md: "Februar 2026"
|
|||
|
|
has_valid_consent -> False
|
|||
|
|
Ergebnis: Erneute Zustimmung erforderlich (KORREKT)
|
|||
|
|
|
|||
|
|
Enforcement-Punkte im Code:
|
|||
|
|
|
|||
|
|
Datei Methode Typ
|
|||
|
|
-------------------------------------------------------
|
|||
|
|
basis14.py call_chat_completion() API-Gateway
|
|||
|
|
basis14.py transcribe_wav() API-Gateway
|
|||
|
|
basis14.py toggle_record() UI-Einstieg
|
|||
|
|
basis14.py _toggle_record_append() UI-Einstieg
|
|||
|
|
basis14.py _diktat_into_widget() UI-Einstieg
|
|||
|
|
basis14.py open_ki_pruefen() UI-Einstieg
|
|||
|
|
basis14.py do_interaktion() UI-Einstieg
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Data Minimization Check
|
|||
|
|
|
|||
|
|
Gespeicherte Felder im Consent-Log (vollstaendige Liste):
|
|||
|
|
|
|||
|
|
action, consent_type, consent_version, hash,
|
|||
|
|
prev_hash, source, timestamp, user_id
|
|||
|
|
|
|||
|
|
Pruefung auf sensible Daten:
|
|||
|
|
|
|||
|
|
Transkript-Inhalte: NICHT gespeichert
|
|||
|
|
KG-Inhalte: NICHT gespeichert
|
|||
|
|
Prompts / KI-Antworten: NICHT gespeichert
|
|||
|
|
API-Keys / Secrets: NICHT gespeichert
|
|||
|
|
Passwoerter: NICHT gespeichert
|
|||
|
|
Patientennamen: NICHT gespeichert
|
|||
|
|
Diagnosen: NICHT gespeichert
|
|||
|
|
Audio-Daten: NICHT gespeichert
|
|||
|
|
|
|||
|
|
Kein Feldwert ueberschreitet 200 Zeichen
|
|||
|
|
(ausser hash/prev_hash mit genau 64 Hex-Zeichen).
|
|||
|
|
|
|||
|
|
Data Minimization: PASS
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. Gesamtbewertung
|
|||
|
|
|
|||
|
|
Pruefpunkt Ergebnis
|
|||
|
|
-------------------------------------------------------
|
|||
|
|
Speicherort + Schema PASS
|
|||
|
|
Beispiel-Logeintraege PASS
|
|||
|
|
Timestamp UTC PASS
|
|||
|
|
Integritaet intakt PASS
|
|||
|
|
Integritaet manipuliert erkannt PASS
|
|||
|
|
Enforcement ohne Consent PASS
|
|||
|
|
Enforcement mit Consent PASS
|
|||
|
|
Enforcement nach Widerruf PASS
|
|||
|
|
Version-Change erfordert Neu-Consent PASS
|
|||
|
|
Data Minimization PASS
|
|||
|
|
|
|||
|
|
GESAMTBEWERTUNG: PASS (10/10)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Reproduzierbarkeit
|
|||
|
|
|
|||
|
|
Der Nachweis kann jederzeit reproduziert werden mit:
|
|||
|
|
|
|||
|
|
python _test_consent_audit.py
|
|||
|
|
|
|||
|
|
Das Skript erzeugt temporaere Testdaten, fuehrt alle Pruefungen
|
|||
|
|
durch und raeumt danach auf (keine persistenten Aenderungen).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. Offene Punkte
|
|||
|
|
|
|||
|
|
- Kein digitaler Signatur-Mechanismus (nur Hash-Kette):
|
|||
|
|
Fuer hoechste Anforderungen waere eine kryptografische
|
|||
|
|
Signatur (z.B. RSA/ECDSA) empfehlenswert.
|
|||
|
|
- Consent bezieht sich auf den Anwendungsbenutzer (Arzt),
|
|||
|
|
nicht auf den Patienten. Die Patienten-Einwilligung erfolgt
|
|||
|
|
ueber das Papierformular (legal/ai_consent.md).
|