This commit is contained in:
2026-03-25 22:03:39 +01:00
parent a0073b4fb1
commit faf4ca10c9
5603 changed files with 1030866 additions and 79 deletions

View File

@@ -0,0 +1,525 @@
# AUDIT-READINESS ASSESSMENT
# AZA / MedWork Februar 2026
**Assessor:** Internes Security-Team (automatisiert)
**Datum:** 2026-02-22
**Scope:** AZA/MedWork Gesamtsystem
**Datenklassifikation:** Besonders schützenswerte Personendaten (Gesundheitsdaten)
**Rechtsrahmen:** DSG (Schweiz, rev. 2023), DSGVO (ergänzend), HIN-Referenzniveau
**Referenzdokumente:** TOMs_AZA_MedWork.md, GAP-Analyse (STEP 3), Handovers STEP 4.16
---
## 1. Technische Sicherheit
---
### 1.1 Transport Security
#### Status: YELLOW
#### Begründung:
- TLS >= 1.2 für alle Backend-Services erzwungen (STEP 4.1, verifiziert in 4.1a)
- Starke Cipher Suites mit PFS (ECDHE+AESGCM, CHACHA20)
- HTTP wird komplett abgelehnt (kein Redirect, Connection Refused)
- Fail-Start bei fehlenden Zertifikaten
- **ABER:** Nur Self-Signed-Zertifikate für Entwicklung vorhanden
- **ABER:** SMTP STARTTLS ist opportunistisch (nicht erzwungen)
- **ABER:** Keine Ende-zu-Ende-Verschlüsselung für E-Mails
#### Blocker für externes Audit:
- Nein, kein harter Blocker. TLS ist implementiert und verifiziert.
- Produktivzertifikate (Let's Encrypt / CA-signiert) müssen vor Go-Live beschafft werden.
#### Empfohlene nächste Schritte:
1. Produktiv-Zertifikate beschaffen (Let's Encrypt / ACME)
2. SMTP-STARTTLS-Erzwingung implementieren (Fehler bei fehlgeschlagenem TLS)
3. S/MIME oder Gateway-Verschlüsselung für medizinische E-Mails evaluieren
---
### 1.2 Authentifizierung
#### Status: YELLOW
#### Begründung:
- Passwort-Login mit bcrypt (cost=12, Salt eingebettet) STEP 4.2
- Legacy-SHA-256-Migration transparent implementiert und verifiziert STEP 4.2a
- TOTP-2FA implementiert (RFC 6238, optional/erzwingbar via ENV) STEP 6
- Backup-Codes (8 Einmal-Codes, SHA-256-gehasht) vorhanden
- Rate-Limiting auf TOTP-Versuche (5/5min)
- RBAC im Workforce Planner (3 Rollen)
- **ABER:** 2FA nur im Desktop-Client, nicht im Workforce Planner (Web-API)
- **ABER:** Kein SSO (SAML/OAuth/OIDC)
- **ABER:** Keine Identitätsprüfung (Videoidentifikation o.ä.)
- **ABER:** Minimale Passwortanforderung (4 Zeichen) ist zu schwach
#### Blocker für externes Audit:
- Ja, teilweise. Für medizinische Systeme wird 2FA in der Regel erwartet.
Im Desktop-Client vorhanden, im Web-API fehlt sie.
#### Empfohlene nächste Schritte:
1. Minimale Passwortlänge auf 8+ Zeichen erhöhen
2. 2FA im Workforce Planner (Web-API) implementieren
3. `AZA_2FA_REQUIRED=1` als Standard für Produktion setzen
---
### 1.3 Secrets Management
#### Status: GREEN
#### Begründung:
- Hardcoded Secret Key entfernt STEP 4.3
- Zentrale Validierung: Mindestlänge 32 Zeichen, keine trivialen Muster
- Fail-Start bei fehlendem oder schwachem Key
- DEV-Modus mit auto-generiertem Key (explizit AZA_ENV=dev)
- Klartext-Credentials aus Config entfernt STEP 4.4
- E-Mail-Passwörter nur via ENV-Variablen
- Incident-Dokumentation für exponiertes Passwort erstellt STEP 4.4a
- TOTP-Secrets verschlüsselt gespeichert (nie Klartext auf Disk)
#### Blocker für externes Audit:
- Nein. Secret Management ist solide implementiert und dokumentiert.
#### Empfohlene nächste Schritte:
1. Passwort beim Mail-Provider rotieren (INCIDENT offen)
2. OS-Keychain-Integration evaluieren (Windows Credential Manager)
3. Secret-Scanning in CI/CD-Pipeline einführen
---
### 1.4 2FA
#### Status: YELLOW
#### Begründung:
- TOTP (RFC 6238) implementiert mit pyotp STEP 6
- QR-Code-Provisioning, Erst-Validierung, Backup-Codes
- Rate-Limiting (5 Versuche / 5 Minuten)
- ENV-Steuerung (AZA_2FA_ENABLED, AZA_2FA_REQUIRED)
- **ABER:** Nur im Desktop-Client (basis14.py), nicht im Workforce Planner
- **ABER:** Aktuell optional (AZA_2FA_REQUIRED=0)
- **ABER:** Kein Hardware-Token-Support (FIDO2/WebAuthn)
#### Blocker für externes Audit:
- Teilweise. 2FA ist implementiert, aber nicht standardmässig erzwungen.
Für HIN-Niveau wäre 2FA-Pflicht erforderlich.
#### Empfohlene nächste Schritte:
1. AZA_2FA_REQUIRED=1 als Produktiv-Standard
2. 2FA im Workforce Planner nachrüsten
3. FIDO2/WebAuthn als Upgrade-Option evaluieren
---
### 1.5 Logging & Monitoring
#### Status: RED
#### Begründung:
- Audit-Log-Modell existiert (AuditLog-Tabelle in workforce_planner)
- log_action()-Funktion definiert
- **ABER:** log_action() wird in keinem API-Endpunkt aufgerufen
- **ABER:** Kein Logging fehlgeschlagener Anmeldeversuche
- **ABER:** Kein zentrales Logging-Framework
- **ABER:** Kein Monitoring, kein Alerting
- **ABER:** Debug-Prints statt strukturiertem Logging
- **ABER:** Kein SIEM
#### Blocker für externes Audit:
- Ja. Fehlende Nachvollziehbarkeit von Datenzugriffen ist ein Kernproblem
für medizinische Systeme (DSG Art. 8, DSGVO Art. 5 Abs. 2).
#### Empfohlene nächste Schritte:
1. log_action() in alle schreibenden API-Endpunkte integrieren
2. Fehlgeschlagene Login-Versuche protokollieren
3. Strukturiertes Logging (Python logging-Modul) einführen
---
## 2. Datenschutz
---
### 2.1 TOMs-Dokumentation
#### Status: GREEN
#### Begründung:
- Vollständiges TOMs-Dokument erstellt (12 Bereiche) STEP 5
- Alle 12 DSG/DSGVO-Bereiche abgedeckt
- Klare Trennung: implementiert vs. nicht implementiert
- 35 Massnahmen implementiert, 62 offen
- Referenzen auf technische Implementierungen vorhanden
#### Blocker für externes Audit:
- Nein. TOMs-Dokument ist vorhanden und audit-tauglich.
Inhaltlich zeigt es aber viele offene Punkte auf.
#### Empfohlene nächste Schritte:
1. TOMs nach jedem Security-Schritt aktualisieren
2. Versionierung/Changelog für TOMs einführen
3. Verantwortlichkeiten pro TOM zuweisen
---
### 2.2 Incident Management
#### Status: YELLOW
#### Begründung:
- Ein Incident wurde formal dokumentiert (Credential Exposure) STEP 4.4a
- Checkliste mit Sofortmassnahmen und Folgeaktionen vorhanden
- Security-Handovers für alle Schritte dokumentiert
- **ABER:** Kein formaler Incident-Response-Plan
- **ABER:** Keine Eskalationsstufen definiert
- **ABER:** Keine Prozesse für DSG Art. 24 (Meldung an EDÖB innert 72h)
- **ABER:** Passwort-Rotation (Incident-Empfehlung) noch offen
#### Blocker für externes Audit:
- Ja, teilweise. Das DSG verlangt eine Meldefähigkeit innert 72h.
Ohne definierten Prozess ist diese nicht gewährleistet.
#### Empfohlene nächste Schritte:
1. Incident-Response-Plan erstellen (Rollen, Eskalation, Fristen)
2. Meldeprozess an EDÖB definieren (72h-Frist)
3. Offene Incident-Massnahme abschliessen (Passwort-Rotation)
---
### 2.3 Datenminimierung
#### Status: RED
#### Begründung:
- Keine formale Datenminimierungsstrategie
- Patientendaten (KG) werden lokal ohne Löschfristen gespeichert
- Keine Klassifikation der verarbeiteten Daten
- Keine Prüfung, ob nur notwendige Daten erhoben werden
- OpenAI API erhält potenziell Patientendaten (Transkription, KG-Generierung)
ohne dokumentierte Notwendigkeitsprüfung
- E-Mail-Inhalte werden vollständig lokal gecacht
#### Blocker für externes Audit:
- Ja. Datenminimierung ist ein Grundprinzip (DSG Art. 6 Abs. 2,
DSGVO Art. 5 Abs. 1 lit. c). Ohne Nachweis ist ein Audit nicht bestehbar.
#### Empfohlene nächste Schritte:
1. Datenverarbeitungsverzeichnis (Art. 12 DSG) erstellen
2. Prüfen welche Daten an OpenAI gesendet werden (Anonymisierung?)
3. Aufbewahrungsfristen für medizinische Daten definieren (kant. Recht: 1020 Jahre)
---
### 2.4 Löschkonzepte
#### Status: RED
#### Begründung:
- Kein Löschkonzept vorhanden
- Keine automatische Datenlöschung
- Keine Löschfunktion für Patientendaten
- Keine Dokumentation der Aufbewahrungsfristen
- Medizinische Daten: kantonale Aufbewahrungspflichten (typisch 10 Jahre)
sind weder dokumentiert noch technisch unterstützt
#### Blocker für externes Audit:
- Ja. Recht auf Löschung (DSG Art. 32, DSGVO Art. 17) nicht umsetzbar.
#### Empfohlene nächste Schritte:
1. Aufbewahrungsfristen pro Datentyp definieren
2. Löschfunktion für Patientendaten implementieren
3. Automatische Löschung nach Ablauf der Aufbewahrungsfrist
---
## 3. Organisation
---
### 3.1 Rollen & Verantwortlichkeiten
#### Status: YELLOW
#### Begründung:
- RBAC im Workforce Planner (ADMIN, MANAGER, EMPLOYEE)
- Rollen-basierte API-Zugriffskontrolle implementiert
- Security-Projekt hat definierte Rollen (Security Engineer, Architekt, Inhaber)
- **ABER:** Kein Datenschutzbeauftragter (DSB) benannt
- **ABER:** Kein IT-Sicherheitsbeauftragter benannt
- **ABER:** Keine Zugriffsmatrix für Patientendaten
- **ABER:** Keine regelmässige Berechtigungsüberprüfung
#### Blocker für externes Audit:
- Teilweise. DSB-Benennung ist für medizinische Praxen in der Schweiz
nicht zwingend (< 250 Mitarbeiter), aber empfohlen.
#### Empfohlene nächste Schritte:
1. Datenschutz-Verantwortlichen benennen (auch wenn nicht DSB-pflichtig)
2. Zugriffsmatrix für Patientendaten erstellen
3. Regelmässige Berechtigungsüberprüfung einführen
---
### 3.2 Schulung
#### Status: RED
#### Begründung:
- Keine Security-Awareness-Schulungen
- Keine Dokumentation für Endbenutzer
- Keine Schulung zum Umgang mit Patientendaten
- Keine Phishing-Awareness
- Keine Einweisungsprozedur
#### Blocker für externes Audit:
- Ja. Fehlende Mitarbeiterschulung ist ein Standard-Audit-Finding.
DSG Art. 8 verlangt angemessene organisatorische Massnahmen.
#### Empfohlene nächste Schritte:
1. Kurzschulung "Datenschutz für Praxismitarbeiter" erstellen (1 Seite)
2. Benutzerhandbuch für AZA/MedWork mit Security-Hinweisen
3. Jährliche Auffrischung dokumentieren
---
### 3.3 Prozesse
#### Status: RED
#### Begründung:
- Kein Change-Management-Prozess
- Kein Release-Management
- Kein formaler Testprozess vor Produktiv-Updates
- Kein Code-Review-Prozess
- Kein Vulnerability-Disclosure-Prozess
- Security-Projekt folgt strukturiertem Vorgehen (Steps), aber nicht formalisiert
#### Blocker für externes Audit:
- Teilweise. Fehlende Prozesse sind ein Risiko, aber für eine
Einzelpraxis nicht zwingend auditrelevant.
#### Empfohlene nächste Schritte:
1. Minimaler Change-Management-Prozess definieren
2. Checkliste vor Produktiv-Deployment
3. Regelmässige Dependency-Prüfung (pip-audit)
---
## 4. Betrieb
---
### 4.1 Backup & Recovery
#### Status: RED
#### Begründung:
- Nur manuelle Dateisystem-Backups (Ordner-Kopien)
- Kein automatisiertes Backup
- Kein Off-Site-Backup
- Keine dokumentierte Recovery-Prozedur
- Keine RTO/RPO definiert
- Keine Wiederherstellungstests
#### Blocker für externes Audit:
- Ja. Verfügbarkeitskontrolle ist eine Grundanforderung (DSG Art. 8).
Ohne Backup-Konzept für medizinische Daten nicht auditierbar.
#### Empfohlene nächste Schritte:
1. Automatisiertes tägliches Backup einrichten
2. RTO/RPO definieren (z.B. RPO=24h, RTO=4h)
3. Quartalsmässige Wiederherstellungstests durchführen
---
### 4.2 Patching
#### Status: RED
#### Begründung:
- Kein dokumentiertes Patch-Management
- Keine automatische Dependency-Prüfung
- Keine Update-Zyklen definiert
- Kein Changelog
#### Blocker für externes Audit:
- Teilweise. Ohne Nachweis aktueller Dependencies besteht Risiko
durch bekannte Schwachstellen.
#### Empfohlene nächste Schritte:
1. `pip-audit` einmalig ausführen und Ergebnis dokumentieren
2. Monatlichen Dependency-Check einführen
3. requirements.txt mit festen Versionen pflegen
---
### 4.3 Monitoring
#### Status: RED
#### Begründung:
- Kein Health-Check-Monitoring
- Kein Alerting bei Service-Ausfall
- Kein Performance-Monitoring
- Keine Anomalie-Erkennung
#### Blocker für externes Audit:
- Teilweise. Für eine Desktop-App weniger kritisch als für Cloud-Services.
#### Empfohlene nächste Schritte:
1. Health-Check-Endpunkt für Backend-Services (bereits vorhanden: /health)
2. Einfaches Uptime-Monitoring (z.B. Skript mit Alerting)
3. Fehlgeschlagene Login-Versuche loggen und alarmieren
---
## 5. Recht
---
### 5.1 Informationspflichten
#### Status: RED
#### Begründung:
- Keine Datenschutzerklärung für Patienten
- Keine Information über Datenverarbeitung beim Einsatz von OpenAI
- Keine Einwilligungserklärung für KI-gestützte Verarbeitung
- DSG Art. 1921 (Informationspflicht) nicht umgesetzt
#### Blocker für externes Audit:
- Ja. Informationspflicht ist zwingend für medizinische Daten.
#### Empfohlene nächste Schritte:
1. Datenschutzerklärung für Patienten erstellen
2. Einwilligungserklärung für KI-Verarbeitung (OpenAI) erstellen
3. Information über Datenübermittlung ins Ausland (OpenAI-Server)
---
### 5.2 Auftragsverarbeitungsverträge (AV)
#### Status: RED
#### Begründung:
- Kein AV/DPA mit OpenAI dokumentiert
- Kein AV/DPA mit Supabase dokumentiert
- Kein AV/DPA mit E-Mail-Provider
- Keine Prüfung der Datenverarbeitungsstandorte
#### Blocker für externes Audit:
- Ja. AV-Verträge sind gesetzlich vorgeschrieben bei Auftragsverarbeitung
(DSG Art. 9, DSGVO Art. 28).
#### Empfohlene nächste Schritte:
1. OpenAI DPA prüfen/abschliessen (existiert als Standard-DPA bei OpenAI)
2. Supabase DPA prüfen/abschliessen
3. Datenverarbeitungsstandorte dokumentieren (Schweiz/EU/US)
---
### 5.3 Privacy Policy / Einwilligungen
#### Status: RED
#### Begründung:
- Keine Privacy Policy vorhanden
- Keine Einwilligungsmechanismen in der Anwendung
- Keine Cookie-/Tracking-Hinweise (bei Web-Komponenten)
- Keine Widerspruchsmöglichkeit
- Keine Auskunftsfunktion (DSG Art. 25)
#### Blocker für externes Audit:
- Ja. Fundamentale rechtliche Anforderung nicht erfüllt.
#### Empfohlene nächste Schritte:
1. Privacy Policy erstellen (Schweizer Recht, medizinischer Kontext)
2. Einwilligungsdialog für KI-Verarbeitung in die App integrieren
3. Auskunftsprozess definieren (Patientenrecht auf Einsicht)
---
## GESAMTBEWERTUNG
### Ampelübersicht
| Bereich | Status | Audit-Blocker |
|---------|:------:|:---:|
| 1.1 Transport Security | YELLOW | Nein |
| 1.2 Authentifizierung | YELLOW | Teilweise |
| 1.3 Secrets Management | GREEN | Nein |
| 1.4 2FA | YELLOW | Teilweise |
| 1.5 Logging & Monitoring | RED | Ja |
| 2.1 TOMs-Dokumentation | GREEN | Nein |
| 2.2 Incident Management | YELLOW | Teilweise |
| 2.3 Datenminimierung | RED | Ja |
| 2.4 Löschkonzepte | RED | Ja |
| 3.1 Rollen | YELLOW | Teilweise |
| 3.2 Schulung | RED | Ja |
| 3.3 Prozesse | RED | Teilweise |
| 4.1 Backup & Recovery | RED | Ja |
| 4.2 Patching | RED | Teilweise |
| 4.3 Monitoring | RED | Teilweise |
| 5.1 Informationspflichten | RED | Ja |
| 5.2 AV-Verträge | RED | Ja |
| 5.3 Privacy Policy | RED | Ja |
### Zählung
| Status | Anzahl |
|--------|:------:|
| GREEN | 2 |
| YELLOW | 5 |
| RED | 11 |
---
### Gesamturteil
#### DSG-konform: NEIN
Hauptgründe: Fehlende Informationspflichten (Art. 1921), fehlende
AV-Verträge (Art. 9), fehlendes Löschkonzept (Art. 32), fehlende
Nachvollziehbarkeit (Art. 8).
#### DSGVO-konform: NEIN
Hauptgründe: Fehlende Privacy Policy, fehlende Einwilligungen für
KI-Verarbeitung, fehlende DPAs, fehlende Datenschutz-Folgenabschätzung
(DSFA/DPIA) für Gesundheitsdatenverarbeitung.
#### Medizinisch auditfähig: NEIN
Hauptgründe: Kein Backup-Konzept, kein Logging, keine Schulung,
keine Informationspflichten gegenüber Patienten.
#### HIN-nah: TEILWEISE
Technische Basis (TLS, Hashing, 2FA) ist vorhanden.
Netzwerk-/PKI-/S/MIME-Ebene fehlt komplett.
Organisatorische Massnahmen fehlen weitgehend.
---
### Priorisierte Top-10-Massnahmen für Audit-Readiness
| Prio | Massnahme | Bereich | Aufwand |
|:----:|-----------|---------|:-------:|
| 1 | Datenschutzerklärung + Einwilligung KI | Recht | Niedrig |
| 2 | OpenAI/Supabase DPA prüfen/abschliessen | Recht | Niedrig |
| 3 | Incident-Passwort-Rotation abschliessen | Incident | Niedrig |
| 4 | Automatisiertes Backup einrichten | Betrieb | Mittel |
| 5 | Audit-Logging in API-Endpunkte integrieren | Technik | Mittel |
| 6 | Datenverarbeitungsverzeichnis erstellen | Datenschutz | Mittel |
| 7 | Löschkonzept + Aufbewahrungsfristen definieren | Datenschutz | Mittel |
| 8 | Kurzschulung Datenschutz erstellen | Organisation | Niedrig |
| 9 | Minimale Passwortlänge auf 8+ erhöhen | Technik | Niedrig |
| 10 | AZA_2FA_REQUIRED=1 als Produktiv-Standard | Technik | Niedrig |
---
*Erstellt: 2026-02-22*
*Nächste Überprüfung: Nach Umsetzung der priorisierten Massnahmen*
*Klassifikation: Intern Nicht zur externen Weitergabe*

View File

@@ -0,0 +1,304 @@
# Technische und Organisatorische Massnahmen (TOMs)
# AZA / MedWork Medizinische Desktop- und Backend-Anwendung
**Version:** 1.0
**Stand:** 2026-02-22
**Geltungsbereich:** AZA/MedWork Gesamtsystem (Desktop-Client, Backend-Services, E-Mail-Modul, Workforce Planner)
**Rechtsgrundlage:** Schweizer Datenschutzgesetz (DSG, rev. 2023), DSGVO (ergänzend)
**Datenklassifikation:** Besonders schützenswerte Personendaten (Gesundheitsdaten, Art. 5 lit. c DSG)
---
## 1. Zugangskontrolle
*Massnahmen, die verhindern, dass Unbefugte Zugang zu Datenverarbeitungsanlagen erhalten.*
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Passwort-geschützter Login | Desktop-Client (basis14.py): Passwort-Dialog bei jedem Start, kein Zugriff ohne Authentifizierung | basis14.py, Zeilen 13181366 |
| Workforce Planner: Token-basierte Authentifizierung | JWT (HS256) mit Ablaufzeit 480 Minuten, Bearer-Token in HTTP-Header | workforce_planner/api/auth.py |
| Backend API-Token | API-Zugriff auf Backend-Services nur mit gültigem Token (Header X-Api-Token) | backend_main.py |
| TLS-Verschlüsselung aller Backend-Services | HTTPS erzwungen für todo_server, transcribe_server, backend_main; HTTP wird abgelehnt (kein Redirect, Connection Refused) | aza_tls.py, STEP 4.1 |
| Fail-Start bei fehlender TLS-Konfiguration | Server startet nicht, wenn AZA_TLS_REQUIRE=1 und Zertifikate fehlen | aza_tls.py |
### Nicht implementiert
- Keine Multi-Faktor-Authentifizierung (2FA/MFA)
- Keine biometrische Zugangskontrolle
- Keine automatische Bildschirmsperre der Anwendung bei Inaktivität
- Kein SSO-Protokoll (SAML/OAuth/OIDC)
- Keine zertifikatsbasierte Client-Authentifizierung
---
## 2. Zugriffskontrolle
*Massnahmen, die sicherstellen, dass Berechtigte nur auf die ihnen zugewiesenen Daten zugreifen können.*
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Rollenbasierte Zugriffskontrolle (RBAC) | Workforce Planner: 3 Rollen (ADMIN, MANAGER, EMPLOYEE) mit Dependency-basierter Prüfung pro API-Endpunkt | workforce_planner/core/enums.py, api/auth.py |
| Rollenprüfung bei schreibenden Operationen | Mitarbeiterverwaltung und Abwesenheitsmanagement erfordern ADMIN oder MANAGER Rolle | routes_employees.py, routes_absences.py |
| Löschoperationen nur für ADMIN | Mitarbeiter-Löschung ist auf ADMIN-Rolle beschränkt | routes_employees.py |
| Profil-Zugriff mit Passwortprüfung | Passwortänderung im Desktop-Client erfordert Eingabe des alten Passworts | basis14.py, Zeilen 15451554 |
### Nicht implementiert
- Keine granulare Datenzugriffskontrolle auf Patienten-/Datensatzebene
- Kein Berechtigungskonzept für Patientenakten (KG)
- Keine Zugriffsmatrix dokumentiert
- Keine regelmässige Überprüfung der Berechtigungen
---
## 3. Weitergabekontrolle
*Massnahmen, die verhindern, dass personenbezogene Daten bei der Übermittlung unbefugt gelesen oder verändert werden.*
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| TLS >= 1.2 für alle Backend-Services | Erzwungen via zentrale Konfiguration; TLS 1.3 wird bevorzugt; starke Cipher Suites (ECDHE+AESGCM, ECDHE+CHACHA20, DHE+AESGCM) | aza_tls.py, STEP 4.1 |
| Perfect Forward Secrecy (PFS) | Cipher Suites erfordern ECDHE oder DHE Schlüsselaustausch | aza_tls.py |
| IMAP über SSL/TLS | E-Mail-Empfang über IMAP4_SSL (Port 993) | aza_email.py |
| SMTP mit STARTTLS | E-Mail-Versand über SMTP mit STARTTLS (Port 587) | aza_email.py |
| Credentials nicht in Dateien | E-Mail-Passwörter werden ausschliesslich aus ENV-Variablen geladen, nie auf Disk geschrieben | aza_email.py, STEP 4.4 |
| Secret Keys nicht hardcoded | JWT-Signing-Key kommt aus ENV (AZA_SECRET_KEY), mit Validierung auf Länge und Komplexität | workforce_planner/config.py, STEP 4.3 |
### Nicht implementiert
- Keine Ende-zu-Ende-Verschlüsselung für E-Mails (kein S/MIME, kein PGP)
- Keine Signierung von E-Mails
- Kein VPN oder Netzwerk-Tunnel
- Keine Zertifikatsverifikation im SMTP-Client (STARTTLS ist opportunistisch)
- Keine Verschlüsselung lokaler Daten auf Disk (SQLite-Datenbank, JSON-Dateien)
---
## 4. Eingabekontrolle
*Massnahmen, die nachvollziehbar machen, wer wann welche Daten eingegeben oder verändert hat.*
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Audit-Log für schreibende Aktionen | Workforce Planner: AuditLog-Tabelle mit user_id, action, entity_type, entity_id, old_values, new_values, timestamp, ip_address, user_agent | workforce_planner/core/models.py, api/audit.py |
| Benutzeridentifikation | Jede API-Aktion wird dem authentifizierten Benutzer zugeordnet (JWT-Token enthält employee_id und role) | workforce_planner/api/auth.py |
### Nicht implementiert
- Audit-Log-Funktion ist definiert, aber nicht in alle API-Endpunkte integriert (log_action wird nur in audit.py referenziert, keine Aufrufe in Routes gefunden)
- Kein Audit-Log für Desktop-Client-Aktionen (basis14.py)
- Kein Audit-Log für E-Mail-Aktionen
- Keine Protokollierung von Datenzugriffen (nur schreibende Aktionen vorgesehen)
- Kein manipulationssicheres Logging (kein WORM, kein Syslog)
---
## 5. Auftragskontrolle
*Massnahmen, die sicherstellen, dass im Auftrag verarbeitete Daten nur gemäss Weisung verarbeitet werden.*
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Externe Dienstleister dokumentiert | OpenAI API für Transkription und KI-Funktionen; Supabase für Cloud-Speicher | basis14.py, aza_config.py |
| API-Key-basierter Zugriff auf externe Dienste | OpenAI-Zugriff nur mit gültigem API-Key aus ENV-Variable | basis14.py |
### Nicht implementiert
- Kein formaler Auftragsverarbeitungsvertrag (AVV/DPA) mit OpenAI dokumentiert
- Kein formaler AVV/DPA mit Supabase dokumentiert
- Keine Prüfung der Datenverarbeitungsstandorte der Unterauftragnehmer
- Keine vertragliche Regelung zur Löschung nach Vertragsende
- Keine Prüfung der technischen Massnahmen der Unterauftragnehmer
---
## 6. Verfügbarkeitskontrolle
*Massnahmen zum Schutz personenbezogener Daten gegen Zerstörung oder Verlust.*
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Lokale Datenspeicherung | Patientendaten, Konfigurationen und Notizen werden lokal als JSON/SQLite gespeichert | aza_persistence.py |
| Manuelle Backup-Kopien | Projektverzeichnis enthält mehrere Backup-Kopien (basis14 - Kopie*.py) | Dateisystem |
| Fail-Start-Mechanismen | Server starten nicht bei fehlender Konfiguration (TLS, Secret Key) verhindert ungesicherten Betrieb | aza_tls.py, workforce_planner/config.py |
### Nicht implementiert
- Kein automatisiertes Backup-Konzept
- Kein Disaster-Recovery-Plan
- Keine Redundanz der Backend-Services
- Kein Monitoring der Dienstverfügbarkeit
- Kein USV-Schutz dokumentiert
- Keine regelmässigen Wiederherstellungstests
---
## 7. Trennungsgebot
*Massnahmen, die sicherstellen, dass zu unterschiedlichen Zwecken erhobene Daten getrennt verarbeitet werden.*
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Modulare Architektur | Separate Module für KG-Diktat (basis14), E-Mail (aza_email), Workforce Planning (workforce_planner), Todo (todo_server), Transkription (transcribe_server) | Dateisystem |
| Getrennte Datenbanken | Workforce Planner: eigene SQLite-Datenbank (workforce_planner.db); Desktop-Client: separate JSON-Config-Dateien | workforce_planner/config.py, aza_persistence.py |
| Getrennte Konfigurationen | Jedes Modul hat eigene Konfigurationsdateien | aza_config.py |
### Nicht implementiert
- Keine mandantenfähige Datentrennung
- Keine formale Datenklassifikation implementiert
- Keine technische Trennung von Produktiv-/Testdaten
- Keine Trennung von medizinischen und administrativen Daten auf Datenbankebene
---
## 8. Incident Management
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Incident-Dokumentation | Formale Incident-Notiz erstellt bei Entdeckung exponierter Credentials | INCIDENT_2026-02-22_CREDENTIAL_EXPOSURE.md |
| Sofortmassnahmen dokumentiert | Checkliste mit Verantwortlichkeiten und Status | INCIDENT_2026-02-22_CREDENTIAL_EXPOSURE.md |
| Security-Handover-Dokumentation | Jeder Sicherheitsschritt wird formal dokumentiert mit Änderungen, Tests und Restrisiken | /security/handovers/ |
### Nicht implementiert
- Kein formaler Incident-Response-Plan
- Keine definierten Eskalationsstufen
- Keine Meldepflicht-Prozesse (DSG Art. 24: Meldung an EDÖB innert 72h)
- Keine automatische Anomalie-Erkennung
- Kein Security Operations Center (SOC)
---
## 9. Backup & Recovery
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Manuelle Dateisystem-Backups | Mehrere datierte Backup-Kopien des Projekts vorhanden | Dateisystem (backup-Ordner) |
| Lokale Datenpersistenz | Alle Daten lokal gespeichert (kein Single Point of Failure durch Cloud-Abhängigkeit) | aza_persistence.py |
### Nicht implementiert
- Kein automatisiertes, regelmässiges Backup
- Keine Versionierung der Datenbanken
- Kein Off-Site-Backup
- Keine dokumentierte Recovery-Prozedur
- Keine Recovery Time Objective (RTO) / Recovery Point Objective (RPO) definiert
- Keine regelmässigen Wiederherstellungstests
---
## 10. Patch- & Update-Management
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Python-Paketmanagement | Dependencies über pip/requirements installierbar | Projektstruktur |
| Aktuelle Kryptographie-Bibliotheken | bcrypt und cryptography-Bibliothek im Einsatz | basis14.py, aza_tls.py |
### Nicht implementiert
- Kein dokumentiertes Patch-Management-Verfahren
- Keine automatische Dependency-Prüfung auf bekannte Schwachstellen (kein pip-audit, kein Dependabot)
- Keine regelmässigen Update-Zyklen definiert
- Keine Testprozedur vor Produktiv-Updates
- Kein Changelog oder Release-Management
---
## 11. Logging & Monitoring
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Audit-Log-Modell | Datenbankmodell für Änderungsprotokoll mit Benutzer, Aktion, Zeitstempel, alte/neue Werte, IP-Adresse | workforce_planner/core/models.py (AuditLog) |
| Debug-Logging | Print-basiertes Debug-Logging in E-Mail-Modul (SMTP/IMAP-Verbindungen) | aza_email.py |
| Sicherheitswarnungen auf stderr | Migrationswarnung bei Klartext-Credentials, Fail-Start-Meldungen bei fehlender Konfiguration | aza_email.py, aza_tls.py, workforce_planner/config.py |
### Nicht implementiert
- Audit-Log-Integration in API-Endpunkte nicht vollständig
- Kein zentrales Logging-Framework (kein strukturiertes Logging)
- Kein Log-Rotation-Mechanismus
- Kein Monitoring-Dashboard
- Keine Alerting-Mechanismen
- Keine Protokollierung fehlgeschlagener Anmeldeversuche
- Kein SIEM (Security Information and Event Management)
---
## 12. Mitarbeiterschulung
### Implementiert
| Massnahme | Umsetzung | Referenz |
|-----------|-----------|----------|
| Keine | Keine formalen Schulungsmassnahmen implementiert | — |
### Nicht implementiert
- Keine Security-Awareness-Schulungen
- Keine Dokumentation für Endbenutzer zum sicheren Umgang
- Keine Schulung zum Umgang mit Patientendaten
- Keine Phishing-Awareness
- Keine dokumentierte Einweisungsprozedur für neue Benutzer
---
## Zusammenfassung
| Bereich | Implementiert | Teilweise | Nicht implementiert |
|---------|:---:|:---:|:---:|
| 1. Zugangskontrolle | 5 | — | 5 |
| 2. Zugriffskontrolle | 4 | — | 4 |
| 3. Weitergabekontrolle | 6 | — | 5 |
| 4. Eingabekontrolle | 2 | — | 5 |
| 5. Auftragskontrolle | 2 | — | 5 |
| 6. Verfügbarkeitskontrolle | 3 | — | 6 |
| 7. Trennungsgebot | 3 | — | 4 |
| 8. Incident Management | 3 | — | 5 |
| 9. Backup & Recovery | 2 | — | 6 |
| 10. Patch- & Update-Management | 2 | — | 5 |
| 11. Logging & Monitoring | 3 | — | 7 |
| 12. Mitarbeiterschulung | 0 | — | 5 |
**Total: 35 Massnahmen implementiert, 62 Massnahmen offen**
### Implementierte Security-Schritte (Bezug)
| Schritt | Massnahme | Status |
|---------|-----------|--------|
| STEP 4.1 | TLS-Pflicht für alle Backend-Services | Erledigt, verifiziert (STEP 4.1a) |
| STEP 4.2 | Sicheres Passwort-Hashing (bcrypt, cost=12) | Erledigt, verifiziert (STEP 4.2a) |
| STEP 4.3 | Hardcoded Secret Key entfernt | Erledigt, getestet |
| STEP 4.4 | Klartext-Credentials entfernt | Erledigt, getestet |
| STEP 4.4a | Incident-Dokumentation Credential Exposure | Erledigt |
---
*Dieses Dokument beschreibt den Ist-Zustand der technischen und organisatorischen
Massnahmen des AZA/MedWork-Systems. Es dient als Grundlage für die Weiterentwicklung
des Sicherheitskonzepts und als Nachweis gegenüber Aufsichtsbehörden.*
*Nächste Überprüfung: Bei Abschluss weiterer Security-Schritte oder spätestens
nach 6 Monaten.*

View File

@@ -0,0 +1,136 @@
# INCIDENT REPORT CREDENTIAL EXPOSURE
# Datum: 2026-02-22
# Klassifikation: SICHERHEITSVORFALL (intern)
---
## 1. Zusammenfassung
Im Rahmen der systematischen Sicherheitsanalyse (STEP 4.4 Klartext-Credentials
entfernen) wurde ein produktives E-Mail-Passwort im Klartext in einer
Konfigurationsdatei des Projekts entdeckt.
---
## 2. Betroffene Komponente
- **Datei:** `aza_email_config.json`
- **Modul:** AZA E-Mail (aza_email.py)
- **Feld:** `password` im `accounts`-Array
- **Betroffener Account:** Produktiver Mail-Account (Details bewusst nicht aufgeführt)
---
## 3. Entdeckung
- **Entdeckt durch:** Automatisierte Security Gap-Analyse (STEP 3) und
bestätigt bei der Implementierung von STEP 4.4
- **Entdeckungsdatum:** 2026-02-22
- **Entdeckungsmethode:** Grep-Suche nach `password`, `secret`, `token`
in allen JSON/YAML/Config-Dateien des Projekts
---
## 4. Risikoanalyse
### Worst-Case-Szenarien
| Szenario | Risiko | Schwere |
|----------|--------|---------|
| Unbefugter Zugriff auf das Dateisystem | Passwort-Exfiltration | HOCH |
| Account-Übernahme (Mail) | Lesen/Senden von E-Mails im Namen des Kontoinhabers | HOCH |
| Mail-Missbrauch | Spam, Phishing, Social Engineering über legitimen Account | HOCH |
| Laterale Bewegung | Falls Passwort wiederverwendet: Zugriff auf weitere Systeme | KRITISCH |
| Datenschutzverletzung | Zugriff auf medizinische Kommunikation (Patientendaten) | KRITISCH |
| Backup-/Export-Exposition | Passwort in Backups, Cloud-Syncs oder Transfers vorhanden | MITTEL |
### Besondere Faktoren
- **Medizinischer Kontext:** E-Mail-Account einer Arztpraxis potenziell
Patientendaten in Mails (DSG/DSGVO-relevant)
- **Expositionsdauer:** Unbekannt. Das Passwort war seit der Erstellung
der Konfigurationsdatei im Klartext gespeichert.
- **Zugriffskreis:** Alle Personen/Systeme mit Lesezugriff auf das
Projektverzeichnis, Backups oder Transfers dieser Datei.
---
## 5. Sofortmassnahmen
| Nr | Massnahme | Status | Verantwortlich |
|----|-----------|--------|----------------|
| 1 | Passwort aus Konfigurationsdatei entfernt | ERLEDIGT (STEP 4.4) | Security Engineer |
| 2 | Code umgestellt auf ENV-basierte Credentials | ERLEDIGT (STEP 4.4) | Security Engineer |
| 3 | Migrationswarnung implementiert | ERLEDIGT (STEP 4.4) | Security Engineer |
| 4 | **Passwort beim Mail-Provider rotieren** | **OFFEN DRINGEND** | Projektinhaber |
| 5 | Prüfung ob Account kompromittiert wurde | OFFEN | Projektinhaber |
---
## 6. Empfohlene Folgeaktionen
### Sofort (innerhalb 24h)
- [ ] **Passwort beim Mail-Provider ändern** (neues, starkes Passwort,
mindestens 16 Zeichen, keine Wiederverwendung)
- [ ] **2FA aktivieren**, falls der Mail-Provider dies unterstützt
- [ ] **Login-Protokolle prüfen**: Gibt es unbekannte Zugriffe auf den
betroffenen Mail-Account?
### Kurzfristig (innerhalb 1 Woche)
- [ ] **Passwort-Wiederverwendung prüfen**: Wurde dasselbe Passwort für
andere Dienste/Systeme verwendet? Falls ja: dort ebenfalls rotieren.
- [ ] **Backups durchsuchen**: Prüfen, ob Kopien der Datei
`aza_email_config.json` in Backups, Cloud-Speicher, USB-Sticks,
E-Mail-Anhängen oder anderen Transfers vorhanden sind.
Falls ja: Passwort dort ebenfalls als exponiert betrachten.
- [ ] **Projekt-Kopien prüfen**: Alle `backup *`-Ordner und Kopien
des Projektverzeichnisses auf Klartext-Passwörter durchsuchen.
### Mittelfristig (Empfehlung)
- [ ] **Secret-Scanning** in CI/CD-Pipeline einführen (z.B. git-secrets,
truffleHog, GitHub Secret Scanning), um zukünftige Klartext-Credentials
automatisch zu erkennen.
- [ ] **OS-Keychain-Integration** evaluieren (Windows Credential Manager),
um Passwörter sicher und benutzerfreundlich zu speichern.
---
## 7. Lessons Learned
### Ursache
Das Passwort wurde direkt im GUI-Dialog eingegeben und ohne
Schutzmassnahmen in eine JSON-Datei auf der Festplatte geschrieben.
Es gab keine Trennung zwischen Konfiguration und Credentials.
### Präventionsmassnahmen (implementiert)
1. **Credentials werden NIE mehr in Dateien geschrieben**
(`_strip_passwords()` in `save_email_config()`)
2. **Credentials kommen ausschliesslich aus ENV-Variablen**
(`AZA_EMAIL_PASSWORD_0`, `_1`, ...)
3. **Migrationswarnung** bei bestehenden Klartext-Passwörtern in der Config
4. **Klartext-Passwörter in JSON werden ignoriert** (kein Auto-Migrate)
### Präventionsmassnahmen (empfohlen, nicht implementiert)
1. Secret-Scanning in CI/CD
2. Pre-Commit-Hooks für Secret-Detection
3. OS-Keychain als sicherer Credential-Store
4. Regelmässige Audits der Konfigurationsdateien
---
## 8. Referenzen
- STEP 3 GAP-Analyse: Lücke #28 identifiziert
- STEP 4.4 Implementierung der Credential-Entfernung
- STEP 4.4 Handover: `/security/handovers/STEP_4_4_CREDENTIALS.md`
---
*Erstellt: 2026-02-22 im Rahmen des AZA/MedWork Security & Compliance Projects*
*Klassifikation: Intern Nicht zur externen Weitergabe bestimmt*

View File

@@ -0,0 +1,32 @@
# STEP 1 HIN TECHNICAL REFERENCE COLLECTION
# Status: ABGESCHLOSSEN
---
## Was gemacht wurde
- Ordner /security/reference/hin_docs/ erstellt
- Öffentlich verfügbare technische Dokumentation von HIN gesammelt
- 16 Originalquellen (hin.ch, support.hin.ch, cdn.hin.ch, msxfaq.de) ausgewertet
- Technische Referenzdatei erstellt: hin_architektur.md
- Quellenverzeichnis erstellt: hin_quellen.md
- Support-Anfrage vorbereitet: QUELLEN_UND_ANLEITUNG.md
## Was geändert wurde
- NEU: /security/reference/hin_docs/hin_architektur.md
- NEU: /security/reference/hin_docs/hin_quellen.md
- NEU: /security/reference/hin_docs/QUELLEN_UND_ANLEITUNG.md
Keine Codeänderungen. Keine Architekturänderungen.
## Offene Punkte
- Offizielle HIN-PDFs sind nicht frei downloadbar
- Support-Anfrage an support@hin.ch ist vorbereitet aber NICHT gesendet (muss User tun)
- HIN Gateway Dokumentation (ZIP) unter https://download.hin.ch/gw/hin-gateway.zip nicht heruntergeladen
## Risiken
- Alle Daten stammen aus öffentlichen Quellen, nicht aus offizieller HIN-Vertragsdokumentation
- Einige technische Details (TLS-Versionen, Cipher Suites) sind in öffentlichen Quellen nicht verfügbar

View File

@@ -0,0 +1,70 @@
# STEP 2 TECHNISCHE ZERLEGUNG VON HIN
# Status: ABGESCHLOSSEN
---
## Was gemacht wurde
Analyse der HIN-Dokumente aus /security/reference/hin_docs/.
Strukturierte Extraktion des HIN Security Stacks in 5 Bereiche.
## Ergebnis (Kurzfassung)
### 1. Transport
- TLS: optional, nicht erzwungen
- S/MIME ist primärer Transportschutz (Legacy)
- Wireguard für Stargate (neue Generation)
- SCION für SSHN-Netzwerk
- TLS-Version, Cipher Suites, PFS: NICHT BELEGT
### 2. Netzwerk
- Geschlossener Vertrauensraum (Gated Community)
- SCION/SSHN mit Schweizer-only Routing
- DDoS-Schutz durch Architektur
- 1 Instanz pro Organisation (Segmentierung)
- Zero Trust, IP-Whitelisting: NICHT BELEGT
### 3. PKI
- Eigene CA: "HIN MGW Issuing CA 2022"
- RSA 4096-bit, SHA256withRSA
- Domain-Zertifikate (10 Jahre Gültigkeit)
- SSHN-Zertifikate (72h Gültigkeit)
- Zentrale Verteilung, geschlossenes System
- Hardware-Token, Smartcard: NICHT BELEGT
### 4. Authentifizierung
- 2FA in drei Varianten (Client, Gateway, Mobil)
- Identitätsprüfung via Videoidentifikation
- SSO für HIN-geschützte Anwendungen
- eID-Typen: Persönlich, Organisation, Team
- SAML/OAuth/OIDC: NICHT BELEGT
### 5. Mail
- S/MIME Gateway-zu-Gateway (nicht Ende-zu-Ende)
- Domain-Zertifikate, automatische Verschlüsselung
- HIN Mail Global: GINA/SEPPMail, SMS-Auth, 30 Tage
- Betreffzeile bei HIN Mail Global: UNVERSCHLÜSSELT
- Backend: SEPPMail-Appliance, Zimbra (IMAP)
## Was geändert wurde
Keine Dateien geändert. Analyse wurde im Chat ausgegeben.
## Offene Punkte
1. TLS-Version, Cipher Suites, PFS nicht dokumentiert
2. mTLS unklar
3. SSO-Protokoll (SAML/OAuth/OIDC) nicht dokumentiert
4. Hardware-Token / Smartcard nicht dokumentiert
5. Client-Zertifikate vs. Software-Token nicht spezifiziert
6. Zero Trust Modell nicht explizit
7. Post-Quanten-Kryptografie nur "vorbereitet", keine Details
8. Wireguard-Konfiguration keine Details
9. Ende-zu-Ende Option nicht dokumentiert
10. IP-Whitelisting nicht dokumentiert
## Risiken
- 10 von 20+ technischen Parametern sind in öffentlichen Quellen NICHT BELEGT
- Gap-Analyse wird in diesen Bereichen auf konservative Annahmen angewiesen sein
- Ohne offizielle HIN-Dokumentation bleiben diese Lücken bestehen

View File

@@ -0,0 +1,209 @@
# =====================================================================
# STEP 3 FORMELLE GAP-ANALYSE (HIN vs. AZA)
# =====================================================================
# Datenquellen: /security/reference/hin_docs/ + Projekt-Code
# Methode: Nur technisch belegbare Fakten
# =====================================================================
## 1. Transport Security
### HIN:
- S/MIME als primärer Transportschutz (nicht TLS)
- TLS optional, nicht erzwungen auf SMTP-Ebene
- Wireguard-Protokoll für Stargate (App-zu-App, kein VPN)
- SCION-Netzwerk für SSHN (any-to-any Verschlüsselung)
- Routing ausschliesslich über Schweizer Netze
### AZA:
- SMTP mit STARTTLS (Port 587) aza_email.py Zeilen 14331436, 29942997
- IMAP über SSL/TLS (Port 993, IMAP4_SSL) aza_email.py Zeilen 1470, 1705
- Keine eigene TLS-Konfiguration (Python-Defaults)
- Keine Zertifikatsverifikation im Code gesetzt
- todo_server.py: reiner HTTP-Server, kein HTTPS Zeile 228
- transcribe_server.py: kein TLS
- backend_main.py: kein TLS
- Supabase-Zugriff über HTTPS aza_config.py Zeile 176
### GAP:
| Aspekt | HIN | AZA | Lücke |
|--------|-----|-----|-------|
| Mail-Verschlüsselung | S/MIME (RSA 4096) | Nur STARTTLS (opportunistisch) | JA |
| App-zu-App Transport | Wireguard | Kein verschlüsselter Kanal | JA |
| Netzwerk-Routing | SCION, nur CH | Internet, global | JA |
| Server-Kommunikation | Verschlüsselt | HTTP (Klartext) | JA |
| TLS-Konfiguration | UNBEKANNT | Python-Defaults | UNBEKANNT |
### Kritikalität: **HIGH**
---
## 2. Netzwerkmodell
### HIN:
- Geschlossener Vertrauensraum (Gated Community)
- SCION/SSHN mit AS-Nummern und Zertifikaten
- DDoS-Schutz durch Architektur
- 1 Instanz pro Organisation (keine Mandantenfähigkeit)
- Redundante Transportwege, automatischer Fail-over
- Governance: HIN, FMH, pharmaSuisse, BAG, SWITCH
### AZA:
- Kein Netzwerk-Perimeter definiert
- Kein VPN
- Kein DDoS-Schutz
- Keine Netzwerk-Segmentierung
- Einzige Netzwerk-Massnahme: Windows-Firewall-Regel für Todo-Server-Port todo_server.py Zeilen 209220
- Backend-Services auf localhost (HTTP)
- Supabase als externer Cloud-Service (HTTPS)
### GAP:
| Aspekt | HIN | AZA | Lücke |
|--------|-----|-----|-------|
| Vertrauensraum | Geschlossen, verifiziert | Offen, kein Perimeter | JA |
| DDoS-Schutz | SCION-basiert | Keiner | JA |
| Segmentierung | 1 Instanz/Organisation | Keine | JA |
| Redundanz | Multi-Path, Fail-over | Keine | JA |
| Governance | 5 Organisationen | Keine | JA |
| VPN | Wireguard (Stargate) | Keiner | JA |
### Kritikalität: **HIGH**
---
## 3. PKI
### HIN:
- Eigene CA: "HIN MGW Issuing CA 2022"
- RSA 4096-bit, SHA256withRSAEncryption
- Domain-Zertifikate (10 Jahre Gültigkeit)
- SSHN-Zertifikate (72h Gültigkeit, automatische Erneuerung)
- Zentrale Zertifikatsverteilung über HIN-Backend
- Geschlossenes System
### AZA:
- Keine PKI
- Keine eigene CA
- Keine Zertifikate (weder Client- noch Server-Zertifikate)
- Kein Zertifikatsmanagement
- Kein CSR-Prozess
- Keine Signierung von Daten oder Kommunikation
### GAP:
| Aspekt | HIN | AZA | Lücke |
|--------|-----|-----|-------|
| Eigene CA | HIN MGW Issuing CA 2022 | Keine | JA |
| Zertifikate | RSA 4096, Domain-Zerts | Keine | JA |
| Zertifikatsverteilung | Zentral, automatisch | Nicht vorhanden | JA |
| Schlüsselmanagement | Zentral über Backend | Nicht vorhanden | JA |
| Hardware-Token | UNBEKANNT | Nicht vorhanden | UNBEKANNT |
### Kritikalität: **HIGH**
---
## 4. Authentifizierung
### HIN:
- 2FA in drei Varianten:
- HIN Client: Passwort + kryptographischer Geräteschlüssel
- HIN Gateway: mTAN/Auth-App + Active Directory
- Mobil: mTAN/Auth-App + HIN Login+Passwort
- Identitätsprüfung via Videoidentifikation
- eID-Typen: Persönlich, Organisation, Team
- SSO für HIN-geschützte Anwendungen
- Berufsqualifikation über Register/Verbände verifiziert
### AZA:
- basis14.py: SHA-256 Passwort-Hash OHNE Salt Zeilen 12981300
- workforce_planner: bcrypt mit Salt auth.py Zeilen 2328
- workforce_planner: JWT mit HS256 auth.py Zeilen 3137
- workforce_planner: Secret Key hardcoded als Fallback "dev-secret-change-in-production" config.py Zeile 19
- workforce_planner: Token-Ablauf 480 Minuten (8h) config.py Zeile 20
- backend_main.py: API-Token via Header "X-Api-Token" Zeilen 154157
- backend_main.py: User-Identifikation via Header "X-User" Zeilen 162164
- Rollen: ADMIN, MANAGER, EMPLOYEE enums.py Zeilen 3336
- Rollenbasierte Zugriffskontrolle mit require_role() auth.py Zeilen 5966
- Keine 2FA / MFA / OTP
- Keine zertifikatsbasierte Authentifizierung
- Keine Identitätsprüfung (Videoidentifikation o.ä.)
- Kein SSO-Protokoll (SAML/OAuth/OIDC)
### GAP:
| Aspekt | HIN | AZA | Lücke |
|--------|-----|-----|-------|
| 2FA | Ja (3 Varianten) | Nein | JA |
| Passwort-Hashing | UNBEKANNT | SHA-256 ohne Salt (basis14) / bcrypt (workforce) | JA (basis14) |
| Secret Key | UNBEKANNT | Hardcoded Fallback | JA |
| Identitätsprüfung | Videoidentifikation | Keine | JA |
| SSO | Ja | Nein | JA |
| Zertifikats-Auth | Ja (Geräteschlüssel) | Nein | JA |
| Token-Ablauf | UNBEKANNT | 480 min (8h) | UNBEKANNT |
| Rollen | eID-basiert (3 Typen) | RBAC (3 Rollen) | TEILWEISE |
### Kritikalität: **HIGH**
---
## 5. Mail-Sicherheit
### HIN:
- S/MIME Gateway-zu-Gateway mit Domain-Zertifikaten (RSA 4096)
- Automatische Verschlüsselung/Entschlüsselung durch Gateway
- HIN Mail Global: GINA/SEPPMail für externe Empfänger
- SMS-Code-Authentifizierung für externe Empfänger
- Domain-Prüfung gegen HIN-Domainliste
- Betreffzeile bei HIN Mail Global: UNVERSCHLÜSSELT
- Header "X-HIN-Encrypted" für Steuerung
### AZA:
- SMTP mit STARTTLS (opportunistisch, nicht erzwungen) aza_email.py
- IMAP über SSL (IMAP4_SSL) aza_email.py
- Keine S/MIME-Implementierung
- Keine PGP/GPG-Implementierung
- Keine Gateway-Verschlüsselung
- Keine Ende-zu-Ende-Verschlüsselung
- Keine Signierung von E-Mails
- Passwörter im Klartext in aza_email_config.json gespeichert
- Keine Zertifikatsverifikation im SMTP/IMAP-Code
### GAP:
| Aspekt | HIN | AZA | Lücke |
|--------|-----|-----|-------|
| Mail-Verschlüsselung | S/MIME (RSA 4096) | Keine | JA |
| Gateway-Verschlüsselung | Automatisch | Keine | JA |
| Externe Empfänger | HIN Mail Global (GINA) | Keine Lösung | JA |
| Signierung | S/MIME Signatur | Keine | JA |
| Credential-Speicherung | UNBEKANNT | Klartext JSON | JA |
| Zertifikatsverifikation | Domain-Zertifikate | Python-Defaults | JA |
### Kritikalität: **HIGH**
---
## OFFENE TECHNISCHE FRAGEN
1. HIN: TLS-Version, Cipher Suites, PFS nicht in hin_docs belegt
2. HIN: Hardware-Token / Smartcard nicht in hin_docs belegt
3. HIN: SSO-Protokoll (SAML/OAuth/OIDC) nicht in hin_docs belegt
4. HIN: Passwort-Hashing-Verfahren nicht in hin_docs belegt
5. HIN: Token-Ablaufzeiten nicht in hin_docs belegt
6. HIN: Credential-Speicherung nicht in hin_docs belegt
7. AZA: Python-Default-TLS-Verhalten hängt von Systemkonfiguration ab nicht geprüft
8. AZA: Supabase-Sicherheitskonfiguration nicht im Scope dieser Analyse
9. AZA: Ob STARTTLS erzwungen oder opportunistisch ist Code zeigt keine Prüfung auf Erfolg
---
## ZUSAMMENFASSUNG
| Bereich | Kritikalität | Anzahl Lücken |
|---------|-------------|---------------|
| 1. Transport Security | HIGH | 5 |
| 2. Netzwerkmodell | HIGH | 6 |
| 3. PKI | HIGH | 5 |
| 4. Authentifizierung | HIGH | 7 |
| 5. Mail-Sicherheit | HIGH | 6 |
| **GESAMT** | **HIGH** | **29 identifizierte Lücken** |
Alle 5 Bereiche haben Kritikalität HIGH.
9 Punkte konnten mangels HIN-Dokumentation nicht vollständig verglichen werden.

View File

@@ -0,0 +1,54 @@
# STEP 3 FORMELLE GAP-ANALYSE (HIN vs. AZA)
# Status: ABGESCHLOSSEN
---
## Ziel des Schrittes
Formale Gegenüberstellung des HIN Security Stacks mit dem aktuellen
AZA/MedWork-Sicherheitszustand. Nur faktenbasierter Vergleich,
keine Empfehlungen, keine Implementierung.
## Konkrete Änderungen
- NEU: /security/handovers/STEP_03_GAP_ANALYSE.md (vollständige Gap-Analyse)
## Betroffene Dateien
Keine Dateien geändert. Nur Analyse-Dokument erstellt.
Analysierte Quelldateien:
- basis14.py (Passwort-Hashing, Login)
- aza_email.py (SMTP/IMAP, Mail-Sicherheit)
- aza_email_config.json (Credential-Speicherung)
- aza_config.py (Supabase-Zugriff)
- backend_main.py (API-Token, User-Header)
- todo_server.py (HTTP-Server, Firewall)
- transcribe_server.py (kein TLS)
- workforce_planner/api/auth.py (JWT, bcrypt)
- workforce_planner/config.py (Secret Key)
- workforce_planner/core/enums.py (Rollen)
- workforce_planner/core/models.py (Employee-Modell)
## Sicherheitsauswirkung
29 Lücken identifiziert, alle 5 Bereiche mit Kritikalität HIGH:
- Transport: 5 Lücken (kein S/MIME, kein verschlüsselter App-Kanal, HTTP-Server)
- Netzwerk: 6 Lücken (kein Perimeter, kein VPN, kein DDoS-Schutz)
- PKI: 5 Lücken (keine CA, keine Zertifikate, kein Schlüsselmanagement)
- Authentifizierung: 7 Lücken (keine 2FA, SHA-256 ohne Salt, hardcoded Secret)
- Mail: 6 Lücken (keine Verschlüsselung, Klartext-Passwörter in Config)
## Offene Punkte
- 9 Vergleichspunkte nicht vollständig bewertbar (HIN-Dokumentation fehlt)
- Supabase-Sicherheitskonfiguration nicht im Scope
- Python-Default-TLS-Verhalten systemabhängig
## Risiken
- Alle 5 Bereiche zeigen fundamentale Lücken zum HIN-Standard
- Besonders kritisch: Klartext-Passwörter in aza_email_config.json
- Besonders kritisch: SHA-256 ohne Salt in basis14.py
- Besonders kritisch: Hardcoded Secret Key "dev-secret-change-in-production"
- Besonders kritisch: HTTP-Server ohne TLS (todo_server, transcribe_server, backend)

View File

@@ -0,0 +1,139 @@
# STEP 10 Technische Einwilligungs-Protokollierung
## Ziel
Jede KI-bezogene Datenverarbeitung muss technisch nachweisbar
durch eine Einwilligung gedeckt sein.
---
## 1. Datenmodell
Jeder Consent-Eintrag enthält:
| Feld | Typ | Beschreibung |
|---|---|---|
| user_id | string | Benutzername 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 (Integritaetskette) |
## 2. Speicherort
- Datei: `aza_consent_log.json` (Projekt-Root)
- Format: JSON-Array (Append-only)
- Manipulationssicherheit: SHA-256-Hash-Kette
(jeder Eintrag referenziert den Hash des vorherigen)
- Kein Überschreiben: Widerruf erzeugt neuen Eintrag,
alter Grant bleibt in der Historie
## 3. Enforcement-Punkte
KI-Funktionen werden an folgenden Stellen blockiert, wenn
keine gueltige Einwilligung vorliegt:
| Stelle | Datei | Methode |
|---|---|---|
| Chat Completion (alle KI-Texte) | basis14.py | call_chat_completion() |
| Transkription | basis14.py | transcribe_wav() |
| Aufnahme starten | basis14.py | toggle_record() |
| Korrektur-Aufnahme | basis14.py | _toggle_record_append() |
| Diktat in Widget | basis14.py | _diktat_into_widget() |
| KI-Prüfung | basis14.py | open_ki_pruefen() |
| Interaktionscheck | basis14.py | do_interaktion() |
Bei fehlendem Consent:
- UI-Einstiegspunkte: Consent-Dialog wird angezeigt
- API-Gateways: RuntimeError wird geworfen
## 4. UI-Elemente
### 4.1 Consent-Dialog (vor erster KI-Nutzung)
- Zeigt den kompletten Text aus legal/ai_consent.md
- Checkbox: "Ich habe den Text gelesen und stimme zu"
- Buttons: "Zustimmen" / "Ablehnen"
- Wird nur angezeigt, wenn kein gueltiger Consent vorliegt
### 4.2 Einstellungsfenster (Datenschutz & Recht)
- Status-Anzeige: "Erteilt" / "Nicht erteilt / widerrufen"
- Button: "KI-Einwilligung widerrufen" / "erteilen"
- Button: "Consent-Log exportieren"
- Bestehende Buttons: Datenschutzerklaerung, KI-Einwilligung
## 5. Versions-Handling
- Die Consent-Version wird aus dem "Stand:"-Feld in
legal/ai_consent.md extrahiert
- Bei Aenderung des Consent-Textes (neues Datum) wird
ein bestehender Consent ungueltig
- Benutzer muss erneut zustimmen
## 6. Audit-Workflow
### Export
```
python -c "from aza_consent import export_consent_log; print(export_consent_log())"
```
Oder ueber Einstellungen -> "Consent-Log exportieren"
### Integritaetspruefung
```
python -c "from aza_consent import verify_chain_integrity; ok, e = verify_chain_integrity(); print('OK' if ok else e)"
```
### Export-Format
```json
{
"export_timestamp": "2026-02-22T...",
"total_entries": 3,
"current_consent_version": "Februar 2026",
"entries": [
{
"user_id": "...",
"consent_type": "ai_processing",
"consent_version": "Februar 2026",
"timestamp": "2026-02-22T...",
"source": "ui",
"action": "grant",
"prev_hash": "0000...0000",
"hash": "a1b2c3..."
}
]
}
```
## 7. Geaenderte / Neue Dateien
| Datei | Aktion |
|---|---|
| aza_consent.py | NEU Consent-Modul (Datenmodell, Storage, Enforcement, Export) |
| basis14.py | GEAENDERT Import aza_consent, Consent-Check an 7 Stellen |
| aza_settings_mixin.py | GEAENDERT Widerruf/Erteil-Button, Status, Export im Einstellungsfenster |
| _test_consent.py | NEU Testskript (14 Tests) |
## 8. Test-Ergebnisse (22.02.2026)
| Test | Ergebnis |
|---|---|
| Ohne Consent -> KI blockiert | PASS |
| Consent erteilen -> KI erlaubt | PASS |
| Widerruf -> KI blockiert | PASS |
| Erneuter Consent -> KI erlaubt | PASS |
| Hash-Kette intakt | PASS |
| Status-Abfrage korrekt | PASS |
| Version-Match | PASS |
| Export erstellt gueltige Datei | PASS |
| User-Historie korrekt | PASS |
| Anderer User -> kein Consent | PASS |
| Gesamt: 14/14 | ALLE BESTANDEN |
## 9. Risiken
| Risiko | Bewertung | Massnahme |
|---|---|---|
| JSON-Datei manuell editierbar | NIEDRIG | Hash-Kette erkennt Manipulation |
| Kein digitaler Signatur-Mechanismus | MITTEL | Fuer Audit: Export + Integritaetspruefung |
| Consent nur auf App-Ebene, nicht Patient | NIEDRIG | Papier-Einwilligung ergaenzt dies |

View File

@@ -0,0 +1,209 @@
# 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).

View File

@@ -0,0 +1,151 @@
# STEP 11 Audit-Logging (Minimal & DSG-konform)
## Ziel
Sicherheitsrelevante Ereignisse nachvollziehbar protokollieren,
ohne sensible Daten (Patientendaten, Prompts, Passwoerter) zu speichern.
---
## 1. Architektur
Neues Modul: aza_audit_log.py
Log-Format: Pipe-separierte Textdatei (eine Zeile pro Ereignis)
TIMESTAMP | EVENT | USER | STATUS | SOURCE | DETAIL
Beispiel:
2026-02-22T21:13:25.419+00:00 | LOGIN_OK | Dr. Mueller | OK | desktop |
Alle Timestamps sind UTC (ISO-8601).
---
## 2. Protokollierte Ereignisse
Event-Typ Beschreibung Wann
------------------------------------------------------------------
APP_START Anwendung gestartet main()
APP_STOP Anwendung beendet nach mainloop()
LOGIN_OK Erfolgreicher Login do_login()
LOGIN_FAIL Fehlgeschlagener Login do_login()
2FA_OK 2FA-Verifizierung erfolgreich do_verify()
2FA_FAIL 2FA-Verifizierung fehlgeschlagen do_verify()
CONSENT_GRANT KI-Einwilligung erteilt on_accept()
CONSENT_REVOKE KI-Einwilligung widerrufen toggle_consent()
AI_TRANSCRIBE KI-Transkription gestartet transcribe_wav()
AI_CHAT KI-Chat-Completion aufgerufen call_chat_completion()
AI_BLOCKED KI-Aufruf ohne Consent blockiert transcribe/chat
PASSWORD_REHASH Legacy-Hash auf bcrypt migriert do_login()
EXPORT Log-Export durchgefuehrt do_export()
---
## 3. Data Minimization (DSG Art. 6)
Was NICHT im Audit-Log gespeichert wird:
- Patientennamen / Patientendaten
- Transkripte / KG-Inhalte
- KI-Prompts / KI-Antworten
- Passwoerter / Passwort-Hashes
- API-Keys / Secrets
- E-Mail-Inhalte
Detail-Feld: Maximal 200 Zeichen, nur Metadaten
(z.B. "model=gpt-5.2", "2FA backup-code").
---
## 4. Log-Rotation
Parameter Standard ENV-Variable
--------------------------------------------------
Max. Dateigroesse 10 MB AZA_AUDIT_ROTATE_MB
Rotierte Dateien 12 AZA_AUDIT_KEEP
Logdatei-Pfad aza_audit.log AZA_AUDIT_LOG
Bei Ueberschreitung der Maximalgroesse:
aza_audit.log -> aza_audit.1.log -> ... -> aza_audit.12.log
Aelteste Datei wird ueberschrieben.
---
## 5. Export
Ueber Einstellungen -> "Logs exportieren (Audit)":
Exportiert sowohl Consent-Log als auch Audit-Log als JSON.
Programmatisch:
python -c "from aza_audit_log import export_audit_log; print(export_audit_log())"
Export-Format:
{
"export_timestamp": "2026-02-22T...",
"total_entries": 12,
"source_file": ".../aza_audit.log",
"entries": [
{
"timestamp": "2026-02-22T...",
"event": "LOGIN_OK",
"user_id": "...",
"status": "OK",
"source": "desktop",
"detail": ""
}
]
}
---
## 6. Integration bestehender Audit-Systeme
Komponente Audit-System Speicherort
-----------------------------------------------------------
Desktop-App (basis14) aza_audit_log.py aza_audit.log
Backend (backend_main) _audit_write() medwork_audit.log
Workforce Planner log_action() + DB workforce_planner.db
Alle drei Systeme sind unabhaengig und koennen
separat exportiert werden.
---
## 7. Geaenderte / Neue Dateien
Datei Aktion
--------------------------------------------------
aza_audit_log.py NEU Audit-Log-Modul
basis14.py GEAENDERT Import + 10 log_event()-Aufrufe
aza_settings_mixin.py GEAENDERT Import + Widerruf-Log + Export
_test_audit_log.py NEU Testskript (23 Tests)
---
## 8. Test-Ergebnisse (22.02.2026)
Test Ergebnis
-------------------------------------------
Events schreiben PASS
12 Zeilen korrekt PASS
6 Felder pro Zeile PASS
Timestamp UTC PASS
Event-Typ korrekt PASS
User korrekt PASS
Status OK/FAIL korrekt PASS
Source = desktop PASS
Statistiken korrekt PASS
Export JSON korrekt PASS
Data Minimization PASS
Pipe-Sanitierung PASS
Gesamt: 23/23 ALLE BESTANDEN
---
## 9. Risiken
Risiko Bewertung Massnahme
--------------------------------------------------------
Log-Datei loeschbar NIEDRIG Backup sichert mit
Kein zentrales SIEM MITTEL Export fuer manuelle Pruefung
Keine Echtzeit-Alarmierung MITTEL Manueller Review empfohlen
Log-Rotation verliert alte Daten NIEDRIG 12 Dateien a 10 MB = 120 MB

View File

@@ -0,0 +1,197 @@
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.

View File

@@ -0,0 +1,211 @@
STEP 12 MONITORING & HEALTH CHECKS (MINIMAL)
Datum: 2026-02-22
Status: ABGESCHLOSSEN
=====================================================================
1. ZIEL
=====================================================================
Minimaler Betriebsnachweis:
- Services leben (Health-Checks)
- Metriken aus bestehenden Logs (kein externer Dienst)
- Integritaetspruefung automatisierbar
- Scheduling dokumentiert
Keine Patientendaten erfasst.
=====================================================================
2. HEALTH-CHECK ENDPOINTS
=====================================================================
Alle Services liefern jetzt unter /health:
{
"status": "ok",
"version": "<app-version>",
"uptime_s": <seconds>,
"tls": true/false
}
a) backend_main.py
URL: https://127.0.0.1:8000/health
Vorher: {"ok": true}
Nachher: {"status": "ok", "version": "0.1.0", "uptime_s": ..., "tls": ...}
b) transcribe_server.py
URL: https://127.0.0.1:8090/health
Vorher: {"status": "ok"}
Nachher: {"status": "ok", "version": "0.1.0", "uptime_s": ..., "tls": ...}
c) todo_server.py
URL: https://127.0.0.1:5111/health
Vorher: Kein /health Endpoint
Nachher: {"status": "ok", "version": "1.0.0", "uptime_s": ..., "tls": ...}
d) Desktop-App (basis14.py)
Kein HTTP-Endpoint (Desktop-App ohne eigenen Server).
Betriebsnachweis ueber Audit-Log:
- APP_START / APP_STOP Events
- LOGIN_OK / LOGIN_FAIL Events
=====================================================================
3. MONITORING-METRIKEN (aza_monitoring.py)
=====================================================================
Quellen: Nur bestehende lokale Logs/Dateien. Kein Cloud-Dienst.
a) Audit-Log Metriken (aus aza_audit_log.py):
- Anzahl LOGIN_FAIL
- Anzahl AI_CHAT + AI_TRANSCRIBE (KI-Calls Zaehler)
- Anzahl AI_BLOCKED
- Anzahl 2FA_FAIL
- Integritaets-Status (PASS/FAIL)
b) Consent-Log Metriken (aus aza_consent.py):
- Anzahl Eintraege
- Integritaets-Status
c) Backup-Metriken (aus backups/ Verzeichnis):
- Anzahl vorhandener Backups
- Letztes Backup (Name + Zeitpunkt)
d) Alert-Severity-Stufen:
- INFO: Zaehler ohne Handlungsbedarf
- WARN: Erhoehte Werte (z.B. > 0 login_fail)
- HIGH: Kritische Schwellen (z.B. >= 10 login_fail)
- CRITICAL: Integritaets-Verletzung
=====================================================================
4. INTEGRITAETS-CHECKS
=====================================================================
Automatisierte Pruefung ueber:
python aza_monitoring.py integrity
Prueft:
- aza_audit_log: verify_all_rotations() (SHA-256 Hash-Kette)
- aza_consent_log: verify_chain_integrity() (SHA-256 Hash-Kette)
Bei Fehler:
- Klarer Log-Eintrag (INTEGRITY_FAIL Event ins Audit-Log)
- Exit-Code 1 (fuer Scheduler-Alerting)
=====================================================================
5. CLI-KOMMANDOS
=====================================================================
python aza_monitoring.py health Health-Checks aller Services
python aza_monitoring.py metrics Metriken aus Logs
python aza_monitoring.py integrity Integritaetspruefung (Exit 0/1)
python aza_monitoring.py alerts Sicherheits-Alerts
python aza_monitoring.py nightly Naechtlicher Gesamtcheck + JSON-Report
python aza_monitoring.py all Alles anzeigen
=====================================================================
6. SCHEDULING-BEISPIELE
=====================================================================
a) Linux (cron):
# Naechtlicher Gesamtcheck um 02:00
0 2 * * * cd /pfad/zu/aza && python aza_monitoring.py nightly >> /var/log/aza_monitoring.log 2>&1
# Stuendlicher Health-Check
0 * * * * cd /pfad/zu/aza && python aza_monitoring.py health >> /var/log/aza_health.log 2>&1
# Integritaet alle 6 Stunden
0 */6 * * * cd /pfad/zu/aza && python aza_monitoring.py integrity || echo "INTEGRITY FAIL" | mail admin@example.com
b) Windows (Task Scheduler):
Aktion: Programm starten
Programm: python
Argumente: aza_monitoring.py nightly
Starten in: C:\Users\surov\Documents\AZA\backup 19.2.26
Trigger: Taeglich, 02:00 Uhr
Alternativ via PowerShell:
$action = New-ScheduledTaskAction `
-Execute "python" `
-Argument "aza_monitoring.py nightly" `
-WorkingDirectory "C:\Users\surov\Documents\AZA\backup 19.2.26"
$trigger = New-ScheduledTaskTrigger -Daily -At "02:00"
Register-ScheduledTask -TaskName "AZA Nightly Monitor" `
-Action $action -Trigger $trigger -Description "AZA Nightly Monitoring"
=====================================================================
7. DATENSCHUTZ-HINWEIS (DATA MINIMIZATION)
=====================================================================
Das Monitoring erfasst KEINE:
- Patientennamen oder -daten
- Transkript-Inhalte oder Prompts
- Passwoerter oder API-Keys
- KI-Antworten
Es werden ausschliesslich Zaehler und Status-Informationen erhoben:
- Anzahl Events pro Typ
- PASS/FAIL Status
- Dateigeroessen und Zeitstempel
- Service-Version und Uptime
Health-Check-Responses enthalten nur technische Metadaten.
=====================================================================
8. TEST-ERGEBNIS
=====================================================================
Testskript: _test_monitoring.py
27 Tests, 0 Fehler.
Tests:
1. Metriken: Audit-Log Eintraege, Integritaet, Backup-Count
2. Alerts: login_fail, ai_calls_total, ai_blocked, 2fa_fail erkannt
3. Integritaets-Check: PASS bei intaktem Log
4. Manipulation: FAIL bei manipuliertem Log, PASS nach Restore
5. Nightly-Report: JSON-Struktur korrekt, Datei geschrieben
6. Data Minimization: Keine Passwoerter/Keys/Transkripte
7. Health-Check Format: _APP_VERSION und _START_TIME vorhanden
=====================================================================
9. BETROFFENE DATEIEN
=====================================================================
Geaendert:
- backend_main.py (/health erweitert: version, uptime_s, tls)
- transcribe_server.py (/health erweitert: version, uptime_s, tls)
- todo_server.py (/health neu hinzugefuegt)
Neu:
- aza_monitoring.py (Monitoring, Metriken, Integrity, CLI)
- _test_monitoring.py (Proof-Skript)
Nicht geaendert:
- basis14.py
- aza_audit_log.py (unveraendert, wird nur gelesen)
- aza_consent.py (unveraendert, wird nur gelesen)
=====================================================================
10. RISIKEN
=====================================================================
- Health-Checks sind unauthentifiziert.
Risiko: Gering (nur Status-Info, keine sensiblen Daten).
Massnahme: Bei Bedarf hinter API-Token schuetzen.
- Monitoring laeuft lokal, kein externes Alerting.
Risiko: Alerts werden nur im JSON-Report gespeichert.
Massnahme: Nightly-Report per Mail weiterleiten (Empfehlung).
- Kein Real-Time-Monitoring.
Risiko: Zwischenzeitliche Ausfaelle werden erst beim naechsten
Scheduled-Check erkannt.
Massnahme: Health-Check-Intervall anpassen (z.B. alle 5 Min).
=====================================================================
11. OFFENE PUNKTE
=====================================================================
Keine.

View File

@@ -0,0 +1,100 @@
# STEP 4.1 TLS-PFLICHT FÜR ALLE BACKEND-SERVICES
# Status: ABGESCHLOSSEN
---
## Ziel
GAP #4: Alle Backend-Services von HTTP auf HTTPS/TLS umstellen.
Fail-Start bei fehlendem Zertifikat im Produktionsmodus.
## Geänderte Dateien
| Datei | Änderung |
|-------|----------|
| **aza_tls.py** | NEU Zentrale TLS-Konfiguration |
| **todo_server.py** | TLS-Integration via create_ssl_context() |
| **transcribe_server.py** | TLS-Integration via uvicorn SSL-Kwargs |
| **backend_main.py** | TLS-Integration via uvicorn SSL-Kwargs |
## TLS-Parameter
| Parameter | Wert |
|-----------|------|
| Minimale TLS-Version | 1.2 (konfigurierbar via ENV) |
| Maximale TLS-Version | 1.3 |
| Cipher Suites | ECDHE+AESGCM, ECDHE+CHACHA20, DHE+AESGCM, DHE+CHACHA20 |
| Ausgeschlossen | aNULL, eNULL, MD5, DSS, RC4, 3DES |
| Perfect Forward Secrecy | Ja (nur ECDHE/DHE Cipher erlaubt) |
| DEV-Zertifikat | RSA 4096-bit, SHA-256, 365 Tage, Self-Signed |
| PROD-Vorbereitung | Pfade über ENV-Variablen konfigurierbar (ACME/Let's Encrypt) |
## Umgebungsvariablen
| Variable | Default | Beschreibung |
|----------|---------|--------------|
| AZA_TLS_CERTFILE | (leer) | Pfad zum Zertifikat (PEM) |
| AZA_TLS_KEYFILE | (leer) | Pfad zum Private Key (PEM) |
| AZA_TLS_MIN_VERSION | "1.2" | Minimale TLS-Version ("1.2" oder "1.3") |
| AZA_TLS_REQUIRE | "1" | "1" = Fail-Start ohne Zertifikat |
## Betroffene Server
| Server | Port | Typ | TLS-Methode |
|--------|------|-----|-------------|
| todo_server | 5111 | stdlib HTTPServer | ssl.wrap_socket() |
| transcribe_server | 8090 | FastAPI/Uvicorn | uvicorn ssl_certfile/ssl_keyfile |
| backend_main | 8000 | FastAPI/Uvicorn | uvicorn ssl_certfile/ssl_keyfile |
| workforce_planner | variabel | FastAPI/Uvicorn | Nicht geändert (kein __main__-Block) |
## Testmethode
### DEV-Zertifikat erstellen:
```
python aza_tls.py
```
### Server starten:
```
set AZA_TLS_CERTFILE=dev-cert.pem
set AZA_TLS_KEYFILE=dev-key.pem
python backend_main.py
```
### Testen:
```
curl https://localhost:8000/health --insecure
```
### Fail-Start testen (ohne Zertifikat):
```
set AZA_TLS_REQUIRE=1
python backend_main.py
→ Muss mit Fehlermeldung abbrechen
```
### DEV-Modus ohne TLS:
```
set AZA_TLS_REQUIRE=0
python backend_main.py
→ Startet auf HTTP mit Warnung
```
## Rest-Risiken
1. **workforce_planner**: Hat keinen eigenen __main__-Block. TLS muss beim
Start via uvicorn CLI konfiguriert werden:
`uvicorn workforce_planner.api.app:app --ssl-certfile=... --ssl-keyfile=...`
2. **Self-Signed Zertifikat**: Browser und Clients zeigen Warnungen.
Für Produktion muss ein CA-signiertes Zertifikat verwendet werden.
3. **Client-Seite**: Die Clients (basis14.py, aza_diktat_mixin.py) müssen
ihre Server-URLs von http:// auf https:// ändern das ist ein separater
Schritt.
4. **Zertifikatsrotation**: Kein automatischer Erneuerungsmechanismus
implementiert. Für PROD wird ACME/certbot empfohlen.
5. **todo_server PWA**: Service Worker erfordert HTTPS für vollständige
Funktionalität auf iPhones dies ist jetzt möglich.

View File

@@ -0,0 +1,157 @@
# STEP 4.1a TLS-ENFORCEMENT VERIFIKATION (BEWEIS)
# Status: ABGESCHLOSSEN
# Datum: 2026-02-22
---
## 1. Listener-Tabelle
| Server | Port | Host | Protokoll (mit TLS) | Protokoll (ohne TLS) |
|--------|------|------|---------------------|----------------------|
| backend_main | 8000 (ENV PORT) | 0.0.0.0 | HTTPS only | Fail-Start (AZA_TLS_REQUIRE=1) |
| transcribe_server | 8090 (ENV TRANSCRIBE_PORT) | 0.0.0.0 | HTTPS only | Fail-Start (AZA_TLS_REQUIRE=1) |
| todo_server | 5111 | 0.0.0.0 | HTTPS only | Fail-Start (AZA_TLS_REQUIRE=1) |
| workforce_planner | variabel | variabel | Über uvicorn CLI | Kein eigener __main__ |
---
## 2. Test-Kommandos und Ergebnisse
### TEST 1: Fail-Start ohne Zertifikat (AZA_TLS_REQUIRE=1)
**Kommando:**
```
$env:AZA_TLS_CERTFILE = ""
$env:AZA_TLS_KEYFILE = ""
$env:AZA_TLS_REQUIRE = "1"
$env:MEDWORK_API_TOKEN = "test123"
python backend_main.py
```
**Ergebnis:**
```
FEHLER: TLS ist erforderlich (AZA_TLS_REQUIRE=1), aber
AZA_TLS_CERTFILE und/oder AZA_TLS_KEYFILE sind nicht gesetzt.
```
Exit Code: 1
**Bewertung: PASS** Server startet nicht ohne Zertifikat.
---
### TEST 2: HTTPS-Verbindung
**Kommando:**
```python
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
r = urllib.request.urlopen('https://127.0.0.1:8444/health', context=ctx)
```
**Ergebnis:**
```
HTTPS: 200 {"ok": true}
```
**Bewertung: PASS** HTTPS funktioniert.
---
### TEST 3: HTTP-Verbindung (muss fehlschlagen)
**Kommando:**
```python
r = urllib.request.urlopen('http://127.0.0.1:8444/health', timeout=5)
```
**Ergebnis:**
```
http.client.RemoteDisconnected: Remote end closed connection without response
```
Exit Code: 1
**Bewertung: PASS** HTTP wird abgelehnt. Kein HTTP-Fallback.
---
### TEST 4: TLS-Version und Cipher
**Kommando:**
```python
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
with ctx.wrap_socket(socket.socket(), server_hostname='localhost') as s:
s.connect(('127.0.0.1', 8444))
print(s.version(), s.cipher())
```
**Ergebnis:**
```
TLS Version: TLSv1.3
Cipher: TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
Bits: 256
```
**Bewertung: PASS** TLS 1.3 mit AES-256-GCM, PFS aktiv.
---
### TEST 5: Zertifikat-Details
**Kommando:**
```python
cert = s.getpeercert(binary_form=True)
c = x509.load_der_x509_certificate(cert)
```
**Ergebnis:**
```
Subject: CN=localhost,O=AZA MedWork DEV
Issuer: CN=localhost,O=AZA MedWork DEV
Key: 4096 bit RSA
Algo: SHA-256
Valid: 2026-02-22 -> 2027-02-22
```
**Bewertung: PASS** RSA 4096-bit, SHA-256, Self-Signed (DEV).
---
### TEST 6: ENV-Hardcoding-Prüfung
**Kommando:** Grep nach "dev-cert.pem" / "dev-key.pem" in *.py
**Ergebnis:**
Nur in `aza_tls.py` Zeilen 114-115 (Generierungsfunktion) und Docstring.
NICHT in todo_server.py, transcribe_server.py, backend_main.py.
Alle Server lesen Zertifikatspfade ausschliesslich aus ENV-Variablen.
**Bewertung: PASS** Keine hardcodierten Zertifikatspfade.
---
## 3. Fix während Verifikation
| Datei | Zeile | Problem | Fix |
|-------|-------|---------|-----|
| aza_tls.py | 93-97 | `ssl_version: ssl.TLSVersion.TLSv1_2` inkompatibel mit uvicorn (ValueError: invalid protocol version 771) | Ersetzt durch `ssl_ciphers: _STRONG_CIPHERS` |
---
## 4. Gesamtbewertung
| Test | Ergebnis |
|------|----------|
| Fail-Start ohne Cert | **PASS** |
| HTTPS-Verbindung | **PASS** |
| HTTP-Ablehnung | **PASS** |
| TLS >= 1.2 | **PASS** (TLS 1.3 verhandelt) |
| Starke Cipher | **PASS** (AES-256-GCM) |
| PFS | **PASS** (ECDHE/DHE only) |
| Zertifikat RSA 4096 | **PASS** |
| Keine hardcodierten Pfade | **PASS** |
**GESAMTERGEBNIS: PASS (8/8)**

View File

@@ -0,0 +1,99 @@
# STEP 4.2 SICHERES PASSWORT-HASHING
# Status: ABGESCHLOSSEN
---
## Ziel
GAP #18: SHA-256 ohne Salt durch moderne KDF ersetzen.
Transparente Migration bestehender Hashes ohne Forced Reset.
## Alte vs. neue Methode
| Parameter | ALT (unsicher) | NEU (sicher) |
|-----------|----------------|--------------|
| Algorithmus | SHA-256 | bcrypt |
| Salt | Keines | Automatisch (eingebettet) |
| Cost-Faktor | n/a | 12 Runden |
| Hash-Format | 64 Hex-Zeichen | $2b$12$... (60 Zeichen) |
| Brute-Force-Resistenz | Minimal (GPU-optimiert) | ~250ms pro Versuch |
| Rainbow-Table-Schutz | Keiner | Salt schützt |
## Parameter
```
bcrypt.gensalt(rounds=12)
```
- Cost: 12 (2^12 = 4096 Iterationen)
- Salt: 16 Bytes, automatisch generiert
- Output: 60-Zeichen-String mit eingebettetem Salt + Params
- Format: $2b$12$<22-char-salt><31-char-hash>
## Geänderte Dateien
| Datei | Zeile | Änderung |
|-------|-------|----------|
| basis14.py | 16-17 | `import bcrypt` hinzugefügt |
| basis14.py | 1298-1300 | `_hash_password()`: SHA-256 → bcrypt |
| basis14.py | 1302-1311 | NEU: `_verify_password()` mit Legacy-Erkennung |
| basis14.py | 1313-1317 | NEU: `_is_legacy_hash()` |
| basis14.py | 1355-1362 | Login: `_verify_password()` + automatischer Rehash |
| basis14.py | 1459 | Registration: nutzt neuen `_hash_password()` (bcrypt) |
| basis14.py | 1545 | Profil: `_verify_password()` für altes Passwort |
| basis14.py | 1554 | Profil: `_hash_password()` für neues Passwort (bcrypt) |
## Migrationslogik
```
Login-Versuch:
1. _verify_password(pw, stored_hash) aufrufen
2. Prüfe: beginnt stored_hash mit "$2b$" oder "$2a$"?
JA → bcrypt.checkpw()
NEIN → SHA-256 Legacy-Vergleich
3. Bei erfolgreicher Anmeldung:
_is_legacy_hash(stored_hash)?
JA → Rehash mit bcrypt, Profil speichern
NEIN → Nichts tun
```
- Kein Forced Reset
- Alter Hash wird beim nächsten Login automatisch ersetzt
- Neuer Hash sofort bei Registration und Passwortänderung
## Legacy-Erkennung
Ein Hash ist Legacy (SHA-256) wenn:
- Er NICHT mit "$2" beginnt (kein bcrypt-Prefix)
- Er exakt 64 Zeichen lang ist (SHA-256 Hex-Output)
## Tests
| Test | Ergebnis |
|------|----------|
| Neuer bcrypt-Hash erstellen | PASS ($2b$12$...) |
| bcrypt verify (korrektes PW) | PASS (True) |
| bcrypt verify (falsches PW) | PASS (False) |
| Legacy SHA-256 erkennen | PASS (is_legacy=True) |
| bcrypt als nicht-Legacy erkennen | PASS (is_legacy=False) |
| Legacy verify (korrektes PW) | PASS (True) |
| Legacy verify (falsches PW) | PASS (False/rejected) |
| Legacy rehash zu bcrypt | PASS (verify nach rehash True) |
## Nicht geändert
- workforce_planner/api/auth.py nutzt bereits bcrypt (cost=default)
- aza_persistence.py importiert hashlib, nutzt es aber nicht für Passwörter
- Backup-Kopien (basis14 - Kopie*.py) bewusst nicht geändert
## Rest-Risiken
1. **bcrypt als Dependency**: Muss installiert sein (`pip install bcrypt`).
Ist bereits Dependency von workforce_planner.
2. **Timing**: Legacy-SHA-256-Vergleich ist schneller als bcrypt.
Ein Timing-Seitenkanalangriff könnte erkennen, ob ein Nutzer
noch einen alten Hash hat. Risiko: minimal (lokale Desktop-App).
3. **workforce_planner cost**: Nutzt bcrypt mit Default-Rounds (10).
Empfehlung: Auf 12 angleichen (separater Schritt).

View File

@@ -0,0 +1,194 @@
# STEP 4.2a HASH-MIGRATION PROOF (AUDIT-NACHWEIS)
# Status: PASS
---
## Test-Setup
- **Datei:** `basis14.py` (Zeilen 12981316)
- **Speicherort:** `kg_diktat_user_profile.json` (JSON, Feld `password_hash`)
- **Testmethode:** Automatisiertes Python-Skript mit Backup/Restore des Original-Profils
- **KDF:** bcrypt, cost=12, Salt eingebettet
- **Legacy:** SHA-256, 64 Hex-Zeichen, kein Salt
- **Testpasswörter:** `AuditTest2026!` (korrekt), `FalschesPasswort` (falsch)
---
## Test 1: Legacy-SHA-256-User anlegen
```
Passwort: AuditTest2026!
SHA-256 Hash: e99f0f4a91440e4a7d89ebd1db548df0eed586dd16e1b3c0e9bb6356220e0f3b
Speicherort: kg_diktat_user_profile.json
```
| Prüfung | Ergebnis |
|---------|----------|
| Profil gespeichert | PASS |
| Hash ist Legacy (64 hex chars) | PASS |
| Hash Länge = 64 | PASS |
| Hash beginnt NICHT mit $2b$ | PASS |
---
## Test 2: Login mit falschem Passwort
```
Passwort: FalschesPasswort
Ergebnis: REJECTED
```
| Prüfung | Ergebnis |
|---------|----------|
| Falsches PW abgelehnt | PASS |
---
## Test 3: Login mit korrektem Passwort + Rehash
### VORHER (Legacy SHA-256):
```
e99f0f4a91440e4a7d89ebd1db548df0eed586dd16e1b3c0e9bb6356220e0f3b
```
### NACHHER (bcrypt):
```
$2b$12$mM1wNUuQJfYMZ23xJRfsJO/JVI0G4ucm9lT.BnTK/LVK8m/gw6CEK
```
| Prüfung | Ergebnis |
|---------|----------|
| Korrektes PW akzeptiert | PASS |
| Hash hat sich geändert | PASS |
| Neuer Hash beginnt mit $2b$ | PASS |
| Neuer Hash ist NICHT Legacy | PASS |
---
## Test 4: Login nach Rehash (bcrypt-Hash)
| Prüfung | Ergebnis |
|---------|----------|
| Korrektes PW nach Rehash | PASS |
| Falsches PW nach Rehash abgelehnt | PASS |
---
## Test 5: Neue Registrierung → direkt bcrypt
```
Neues Passwort: NeuerUser2026!
bcrypt Hash: $2b$12$MdhU4H6CihlPMecPxRGgHuZ0rRJw.QXd1B0tqr4A8xK...
```
| Prüfung | Ergebnis |
|---------|----------|
| Hash ist bcrypt | PASS |
| Hash ist NICHT Legacy | PASS |
| Verify korrekt | PASS |
| Verify falsch abgelehnt | PASS |
---
## Test 6: Passwortänderung → bcrypt
```
Neuer Hash: $2b$12$62I3tJxk09DaPmmu.6SsEeTgSp6UJReaJtSzs57SFO6...
```
| Prüfung | Ergebnis |
|---------|----------|
| Hash ist bcrypt | PASS |
| Altes PW abgelehnt | PASS |
| Neues PW akzeptiert | PASS |
---
## Code-Verifikation
### _hash_password() Zeile 12981301
```python
@staticmethod
def _hash_password(pw: str) -> str:
return bcrypt.hashpw(pw.encode("utf-8"), bcrypt.gensalt(rounds=12)).decode("utf-8")
```
→ Erzeugt bcrypt-Hash mit cost=12 und eingebettetem Salt.
### _verify_password() Zeile 13031309
```python
@staticmethod
def _verify_password(pw: str, stored_hash: str) -> bool:
if stored_hash.startswith("$2b$") or stored_hash.startswith("$2a$"):
return bcrypt.checkpw(pw.encode("utf-8"), stored_hash.encode("utf-8"))
legacy = hashlib.sha256(pw.encode("utf-8")).hexdigest()
return legacy == stored_hash
```
→ Erkennt bcrypt-Hashes am Prefix. Fällt auf SHA-256-Vergleich zurück.
### _is_legacy_hash() Zeile 13111316
```python
@staticmethod
def _is_legacy_hash(stored_hash: str) -> bool:
if not stored_hash:
return False
return not stored_hash.startswith("$2") and len(stored_hash) == 64
```
→ Erkennt alte 64-Zeichen SHA-256-Hashes.
### Login mit Rehash Zeile 13631367
```python
stored = self._user_profile.get("password_hash", "")
if self._verify_password(pw, stored):
if self._is_legacy_hash(stored):
self._user_profile["password_hash"] = self._hash_password(pw)
save_user_profile(self._user_profile)
dlg.destroy()
```
→ Bei erfolgreichem Login: Legacy-Hash automatisch durch bcrypt ersetzt.
### Registrierung Zeile 1465
```python
"password_hash": self._hash_password(pw),
```
→ Nutzt direkt bcrypt.
### Profiländerung (altes PW prüfen) Zeile 1545
```python
if old_hash and not self._verify_password(pw_old_e.get(), old_hash):
```
→ Verifiziert mit _verify_password (bcrypt + Legacy-kompatibel).
### Profiländerung (neues PW setzen) Zeile 1554
```python
pw_hash = self._hash_password(new_pw)
```
→ Nutzt direkt bcrypt.
---
## Gesamtergebnis
| Nr | Testfall | Ergebnis |
|----|----------|----------|
| 1 | Legacy-Hash anlegen & erkennen | PASS |
| 2 | Falsches PW → abgelehnt | PASS |
| 3 | Korrektes PW → akzeptiert + Rehash | PASS |
| 4 | Login nach Rehash funktioniert | PASS |
| 5 | Registrierung schreibt bcrypt | PASS |
| 6 | Passwortänderung schreibt bcrypt | PASS |
**18/18 Einzelprüfungen: PASS**
**0 Fixes notwendig**
**Original-Profil wiederhergestellt**
---
## Bewertung: PASS
Alle Anforderungen erfüllt:
- Legacy SHA-256 wird erkannt
- Login mit korrektem/falschem PW korrekt
- Rehash passiert automatisch beim Login
- Nach Rehash ist der gespeicherte Hash bcrypt
- Neue Registrierungen und Passwortänderungen verwenden direkt bcrypt
- Kein Forced Reset notwendig

View File

@@ -0,0 +1,162 @@
# STEP 4.3 HARDCODED SECRET KEY ENTFERNT (LÜCKE #19)
# Status: ABGESCHLOSSEN
---
## Fundstellen
| Datei | Zeile | Problem |
|-------|-------|---------|
| `workforce_planner/config.py` | 18 | `SECRET_KEY = os.getenv("WP_SECRET_KEY", "dev-secret-change-in-production")` Hardcoded Fallback-Secret |
| `workforce_planner/api/auth.py` | 35, 47 | Konsument: JWT encode/decode mit `SECRET_KEY` |
Keine weiteren hardcoded Secrets gefunden:
- `basis14.py`: OPENAI_API_KEY kommt aus ENV, kein Fallback
- `basis14.py`: MEDWORK_API_TOKEN kommt aus ENV oder Datei, kein hardcoded Wert
- `aza_email_config.json`: Passwörter im Klartext (separates GAP, nicht in diesem Schritt)
---
## Neue ENV-Variablen
| Variable | Pflicht | Beschreibung |
|----------|---------|-------------|
| `AZA_SECRET_KEY` | Ja (ausser DEV) | JWT-Signing-Key, min. 32 Zeichen |
| `AZA_ENV` | Nein | `dev` = erlaubt auto-generierten Key |
Alte Variable `WP_SECRET_KEY` wird **nicht mehr verwendet**.
---
## Implementierung
### workforce_planner/config.py (komplett neu)
**ALT:**
```python
SECRET_KEY = os.getenv("WP_SECRET_KEY", "dev-secret-change-in-production")
```
**NEU:**
```python
def _load_secret_key() -> str:
key = os.getenv("AZA_SECRET_KEY", "").strip()
env_mode = os.getenv("AZA_ENV", "").strip().lower()
# Kein Key: DEV auto-gen oder Fail-Start
if not key:
if env_mode == "dev":
return secrets.token_hex(64) # temporär, nur diese Session
sys.exit(1) # Fehlermeldung + Exit
# Zu kurz (< 32 Zeichen): Fail-Start
if len(key) < 32:
sys.exit(1)
# Triviales Muster: Fail-Start
for pattern in ("dev", "test", "password", "secret", ...):
if key.startswith(pattern) und nicht-alphanumerisches Folgezeichen:
sys.exit(1)
return key
SECRET_KEY = _load_secret_key()
```
### workforce_planner/api/auth.py
Keine Änderung nötig importiert weiterhin `SECRET_KEY` aus `config.py`.
Die Variable hat denselben Namen, der Wert kommt jetzt validiert aus ENV.
---
## Fail-Start Verhalten
| Szenario | Ergebnis |
|----------|----------|
| Kein `AZA_SECRET_KEY`, kein `AZA_ENV=dev` | Exit 1 + Fehlermeldung |
| `AZA_ENV=dev`, kein Key | OK (auto-gen, Warnung auf stderr) |
| Key < 32 Zeichen | Exit 1 + "zu kurz" |
| Key mit trivialem Muster ("dev-...", "test-...", "password...") | Exit 1 + "triviales Muster" |
| Gültiger Key >= 32 Zeichen | OK |
| Nur `WP_SECRET_KEY` gesetzt (alt) | Exit 1 (wird ignoriert) |
---
## Testkommandos + erwartete Outputs
### 1. Fail-Start (kein Key)
```bash
python -c "from workforce_planner.config import SECRET_KEY"
# → Exit 1: FEHLER: AZA_SECRET_KEY ist nicht gesetzt.
```
### 2. DEV-Modus (auto-gen)
```bash
AZA_ENV=dev python -c "from workforce_planner.config import SECRET_KEY; print(len(SECRET_KEY))"
# → 128 (hex-encoded 64 Bytes) + Warnung auf stderr
```
### 3. Zu kurzer Key
```bash
AZA_SECRET_KEY=short123 python -c "from workforce_planner.config import SECRET_KEY"
# → Exit 1: FEHLER: AZA_SECRET_KEY ist zu kurz (8 Zeichen, Minimum: 32)
```
### 4. Triviales Muster
```bash
AZA_SECRET_KEY="test-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" python -c "from workforce_planner.config import SECRET_KEY"
# → Exit 1: FEHLER: AZA_SECRET_KEY enthält triviales Muster ('test')
```
### 5. Gültiger Key
```bash
AZA_SECRET_KEY=$(python -c "import secrets; print(secrets.token_hex(64))") python -c "from workforce_planner.config import SECRET_KEY; print('OK:', len(SECRET_KEY), 'chars')"
# → OK: 128 chars
```
---
## Testergebnis (automatisiert)
```
12/12 PASS, 0/12 FAIL
GESAMTBEWERTUNG: PASS
```
| Test | Ergebnis |
|------|----------|
| Fail-Start ohne Key | PASS |
| Fehlermeldung enthält 'AZA_SECRET_KEY' | PASS |
| DEV auto-gen Key | PASS |
| Key geladen (128 chars) | PASS |
| Warnung ausgegeben | PASS |
| Fail-Start kurzer Key | PASS |
| Fehlermeldung 'zu kurz' | PASS |
| Fail-Start alter Fallback | PASS |
| Fail-Start triviales Pattern (lang) | PASS |
| Start mit gültigem Key | PASS |
| Key geladen (64 chars) | PASS |
| WP_SECRET_KEY allein -> Fail-Start | PASS |
---
## Session/Token-Invalidierung
**Impact:** Bestehende JWT-Tokens (HS256), die mit dem alten Fallback-Key
`"dev-secret-change-in-production"` signiert wurden, werden nach dem
Setzen eines neuen `AZA_SECRET_KEY` **ungültig**.
- Betroffene Nutzer müssen sich **einmalig neu anmelden**.
- Dies betrifft nur den `workforce_planner` (Arbeitsplan-Modul).
- `basis14.py` verwendet keine JWT-Tokens (nur lokales Passwort-Hashing).
- **Keine komplexe Rotation** implementiert (nicht im Scope dieses Schrittes).
- Bei Produktivbetrieb: Key einmalig setzen und dauerhaft beibehalten.
---
## Geänderte Dateien
| Datei | Änderung |
|-------|----------|
| `workforce_planner/config.py` | Hardcoded Fallback entfernt, `_load_secret_key()` mit Validierung + Fail-Start implementiert |

View File

@@ -0,0 +1,166 @@
# STEP 4.4 KLARTEXT-CREDENTIALS ENTFERNT (LÜCKE #28)
# Status: ABGESCHLOSSEN
---
## Fundstellen
| Datei | Problem |
|-------|---------|
| `aza_email_config.json` | Klartext-Passwort im `password`-Feld: `"password": "Asdfasdf22@@As96k324"` |
Keine weiteren Klartext-Credentials in JSON/YAML/INI-Dateien gefunden.
**Hinweis:** Das hier entfernte Passwort war ein echtes Produktivpasswort.
Es sollte umgehend beim Mail-Provider geändert werden.
---
## Neue ENV-Variablen
| Variable | Beschreibung |
|----------|-------------|
| `AZA_EMAIL_PASSWORD_0` | Passwort für das erste E-Mail-Konto |
| `AZA_EMAIL_PASSWORD_1` | Passwort für das zweite E-Mail-Konto (falls vorhanden) |
| `AZA_EMAIL_PASSWORD_N` | Passwort für das N-te Konto (0-basiert) |
### Setzen unter Windows:
```cmd
set AZA_EMAIL_PASSWORD_0=MeinSicheresPasswort
```
### Setzen unter Linux/Mac:
```bash
export AZA_EMAIL_PASSWORD_0="MeinSicheresPasswort"
```
### Dauerhaft (Windows PowerShell):
```powershell
[Environment]::SetEnvironmentVariable("AZA_EMAIL_PASSWORD_0", "MeinPasswort", "User")
```
---
## Geänderte Dateien
| Datei | Änderung |
|-------|----------|
| `aza_email.py` | Neue Funktionen: `_get_account_password()`, `_strip_passwords()`, `_check_plaintext_migration()` |
| `aza_email.py` | `load_email_config()`: Lädt Passwörter aus ENV, ignoriert Klartext in JSON, gibt Warnung |
| `aza_email.py` | `save_email_config()`: Strippt `password` und `_password` vor dem Schreiben |
| `aza_email.py` | Alle IMAP/SMTP-Stellen: `acc.get("password")``acc.get("_password")` |
| `aza_email.py` | Account-Dialog: Passwort wird als `_password` (RAM-only) gespeichert |
| `aza_email_config.json` | Klartext-Passwort entfernt |
---
## Architektur
### Passwort-Fluss (NEU):
```
ENV (AZA_EMAIL_PASSWORD_0)
load_email_config() ──► acc["_password"] (nur RAM)
IMAP/SMTP Login ──► acc.get("_password", "")
save_email_config() ──► _strip_passwords() ──► JSON OHNE Passwort
```
### Passwort-Fluss (GUI-Eingabe):
```
Account-Dialog (Passwort-Feld)
save_account() ──► acc["_password"] = pw_input (nur RAM)
_save_config() ──► save_email_config() ──► _strip_passwords() ──► JSON OHNE Passwort
```
Das `_password`-Feld existiert NUR im RAM. Es wird NIE in JSON geschrieben.
Das `password`-Feld wird beim Laden aus JSON ignoriert und beim Speichern entfernt.
---
## Migrationsverhalten
Wenn `aza_email_config.json` noch ein `password`-Feld enthält:
1. **Warnung auf stderr:**
```
SICHERHEITSWARNUNG: Klartext-Passwoerter in aza_email_config.json gefunden!
Betroffene Konten: andre.surovy@haut-winterthur.ch
Bitte entfernen und stattdessen ENV-Variablen setzen:
AZA_EMAIL_PASSWORD_0
Die Passwoerter in der Datei werden IGNORIERT.
```
2. **Klartext-Passwort wird NICHT übernommen** (kein Auto-Migrate)
3. **Benutzer muss ENV-Variable setzen**, damit E-Mail funktioniert
4. **Beim nächsten Speichern** wird das `password`-Feld automatisch entfernt
---
## Fail-Start Verhalten
| Szenario | Ergebnis |
|----------|----------|
| `AZA_EMAIL_PASSWORD_0` gesetzt | E-Mail funktioniert |
| `AZA_EMAIL_PASSWORD_0` nicht gesetzt | E-Mail-Abruf zeigt: "Konto-Daten unvollständig" |
| Klartext-PW in JSON | Warnung + wird ignoriert |
| GUI-Passworteingabe | Funktioniert für Sitzung (nicht persistent) |
---
## Testergebnis
```
12/12 PASS, 0/12 FAIL
GESAMTBEWERTUNG: PASS
```
| Test | Ergebnis |
|------|----------|
| Kein Passwort in JSON | PASS |
| Warnung auf stderr bei Klartext | PASS |
| Passwort NICHT in geladenen Daten | PASS |
| ENV-PW in _password Feld | PASS |
| Kein password Feld nach Laden | PASS |
| Kein password in gespeicherter Datei | PASS |
| Kein _password in gespeicherter Datei | PASS |
| password entfernt (Konto 1) | PASS |
| password entfernt (Konto 2) | PASS |
| _password entfernt (nie auf Disk) | PASS |
| Andere Felder erhalten | PASS |
| Kein print mit password-Wert | PASS |
---
## Rest-Risiken
1. **Passwort im RAM:** Während der Sitzung liegt das Passwort im RAM
(Python-String). Für eine Desktop-App akzeptabel.
2. **ENV-Variable sichtbar:** `AZA_EMAIL_PASSWORD_0` kann in Prozesslisten
sichtbar sein. Empfehlung für Zukunft: OS-Keychain-Integration
(Windows Credential Manager / macOS Keychain).
3. **Altes Passwort exponiert:** Das Passwort `Asdfasdf22@@As96k324` war
in der JSON-Datei gespeichert. Es sollte beim Provider geändert werden.
4. **Backup-Dateien:** Die Kopie-Dateien (`aza_email - Kopie.py`, etc.)
enthalten noch den alten Code. Diese sind Backups und nicht aktiv.
---
## Repo-Hygiene
- Kein Git-Repository vorhanden → kein `.gitignore`-Eintrag nötig
- Kein History-Rewrite nötig
- `aza_email_config.json` wurde direkt bereinigt (Passwort entfernt)

View File

@@ -0,0 +1,216 @@
# STEP 6 TOTP-ZWEI-FAKTOR-AUTHENTIFIZIERUNG
# Status: ABGESCHLOSSEN
---
## Architektur
### Komponenten
```
aza_totp.py Zentrales TOTP-Modul (RFC 6238)
basis14.py GUI-Integration (Login, Profil, Setup)
pyotp (2.9.0) TOTP-Implementierung (RFC 6238 kompatibel)
qrcode[pil] (8.2) QR-Code-Generierung
```
### Flow
```
Login-Dialog
Passwort prüfen ──► FAIL → Fehlermeldung
▼ OK
2FA aktiv? ──► NEIN + 2FA_REQUIRED → Erzwinge 2FA-Setup
│ │
▼ JA ▼
TOTP-Dialog ──────────────────────── 2FA-Setup-Dialog
│ │
▼ ▼
Code prüfen QR-Code scannen
│ Code validieren
├─ TOTP OK → Login │
├─ Backup-Code OK → Login Backup-Codes anzeigen
└─ FAIL → Fehlermeldung │
2FA aktiviert
```
---
## Datenmodell
### Profil (kg_diktat_user_profile.json)
```json
{
"name": "Dr. Beispiel",
"specialty": "Dermatologie",
"clinic": "Praxis XY",
"password_hash": "$2b$12$...",
"totp_active": true,
"totp_secret_enc": "Base64-verschlüsselter-TOTP-Secret",
"backup_codes": [
"sha256-hash-code-1",
"sha256-hash-code-2",
"",
"sha256-hash-code-4",
...
]
}
```
| Feld | Typ | Beschreibung |
|------|-----|-------------|
| `totp_active` | boolean | 2FA aktiviert/deaktiviert |
| `totp_secret_enc` | string | TOTP-Secret, XOR-verschlüsselt mit Passwort-Hash, Base64 |
| `backup_codes` | string[] | SHA-256-Hashes der Backup-Codes; leer = verbraucht |
---
## TOTP-Parameter
| Parameter | Wert |
|-----------|------|
| Algorithmus | TOTP (RFC 6238) |
| Hash | SHA-1 (Standard per RFC) |
| Zeitschritt | 30 Sekunden |
| Code-Länge | 6 Ziffern |
| Gültigkeitsfenster | +-1 (90 Sekunden total) |
| Secret-Länge | 160 bit (32 Base32-Zeichen) |
---
## Sicherheitsmassnahmen
### Secret-Verschlüsselung
- TOTP-Secret wird NIE im Klartext gespeichert
- Verschlüsselung: XOR mit SHA-256(Benutzer-Passwort)
- Encoding: Base64
- Entschlüsselung nur mit korrektem Passwort möglich
- Bei falschem Passwort: leerer String (kein Crash)
### Backup-Codes
- 8 Einmal-Codes (8 Zeichen, hex, uppercase)
- Gespeichert als SHA-256-Hashes
- Verbrauchte Codes werden zu leerem String
- Case-insensitive Eingabe
- HMAC-basierter Vergleich (timing-safe)
### Rate-Limiting
- Max. 5 TOTP-Versuche pro 5 Minuten pro Benutzer
- Nach Erreichen: auch korrekter Code wird blockiert
- Im RAM gehalten (Reset bei Neustart)
---
## ENV-Variablen
| Variable | Default | Beschreibung |
|----------|---------|-------------|
| `AZA_2FA_ENABLED` | `1` | 2FA-Feature verfügbar |
| `AZA_2FA_REQUIRED` | `0` | 2FA ist Pflicht für alle Benutzer |
### Verhalten
| AZA_2FA_ENABLED | AZA_2FA_REQUIRED | Ergebnis |
|:---:|:---:|---|
| 0 | 0 | 2FA komplett deaktiviert, kein Button im Profil |
| 1 | 0 | 2FA optional, Aktivierung im Profil |
| 1 | 1 | 2FA Pflicht, Setup nach erstem Login erzwungen |
| 0 | 1 | Feature deaktiviert, Required ignoriert |
---
## Recovery
- Wiederherstellung NUR über Backup-Codes
- Kein Admin-Reset ohne Prüfung
- Kein E-Mail-Recovery
- Backup-Codes werden nach 2FA-Aktivierung einmalig angezeigt
- Benutzer muss Codes selbst sichern (Kopieren/Ausdrucken)
- Bei aufgebrauchten Backup-Codes: Profil-Datei manuell bereinigen (Admin-Eingriff)
---
## Geänderte / Neue Dateien
| Datei | Änderung |
|-------|----------|
| `aza_totp.py` | NEU: Zentrales TOTP-Modul |
| `basis14.py` | Import: pyotp, qrcode, PIL.ImageTk, aza_totp |
| `basis14.py` | `_show_password_login()`: 2FA-Check nach Passwort |
| `basis14.py` | `_show_totp_login()`: NEU TOTP-Code-Dialog |
| `basis14.py` | `_show_2fa_setup()`: NEU QR-Code + Erst-Validierung |
| `basis14.py` | `_show_backup_codes()`: NEU Backup-Code-Anzeige |
| `basis14.py` | `_show_profile_editor()`: 2FA-Aktivierung/Deaktivierung |
---
## Dependencies
```
pyotp==2.9.0 # TOTP RFC 6238
qrcode[pil]==8.2 # QR-Code-Generierung
```
---
## Testergebnis
```
24/24 PASS, 0/24 FAIL
GESAMTBEWERTUNG: PASS
```
| Test | Ergebnis |
|------|----------|
| Secret-Generierung (Base32, 32 Zeichen) | PASS |
| Secrets sind einzigartig | PASS |
| Provisioning URI (otpauth://) | PASS |
| URI enthält Issuer | PASS |
| URI enthält Secret | PASS |
| Korrekter Code akzeptiert | PASS |
| Falscher Code abgelehnt | PASS |
| Leerer Code abgelehnt | PASS |
| Abgelaufener Code (90s) abgelehnt | PASS |
| 8 Backup-Codes generiert | PASS |
| Code-Format (8 hex chars) | PASS |
| Codes einzigartig | PASS |
| Hashes SHA-256 | PASS |
| Backup-Code Lookup | PASS |
| Falscher Backup-Code abgelehnt | PASS |
| Case-insensitive | PASS |
| Einmalnutzung | PASS |
| Invalidierter Code abgelehnt | PASS |
| Secret-Verschlüsselung | PASS |
| Verschlüsselt != Klartext | PASS |
| Entschlüsselung korrekt | PASS |
| Falsches PW = falsches Secret | PASS |
| Rate-Limit greift nach 5 Versuchen | PASS |
| Rate-Limit blockiert auch korrekte Codes | PASS |
---
## Risiken
1. **XOR-Verschlüsselung:** Für eine Desktop-App akzeptabel, aber kryptographisch
schwächer als AES. Upgrade auf Fernet/AES bei Bedarf.
2. **Secret an Passwort gebunden:** Bei Passwortänderung muss das TOTP-Secret
neu verschlüsselt werden. Aktuell nicht automatisch 2FA muss nach
Passwortänderung neu eingerichtet werden.
3. **Rate-Limit im RAM:** Wird bei Neustart zurückgesetzt. Für Desktop-App
akzeptabel (kein Netzwerk-Angriff möglich).
4. **Kein TOTP für workforce_planner:** Die 2FA ist nur im Desktop-Client
(basis14.py) implementiert. Der workforce_planner (Web-API) hat noch
keine 2FA-Integration.
5. **SHA-1 in TOTP:** RFC 6238 spezifiziert SHA-1 als Standard. Alle gängigen
Authenticator-Apps (Google, Microsoft, Authy) erwarten SHA-1.

View File

@@ -0,0 +1,59 @@
# STEP 8 Datenschutzerklärung & KI-Einwilligung
## Ziel
Erstellung rechtlich belastbarer Texte für DSG (Schweiz), DSGVO (EU),
medizinische Daten und KI-Verarbeitung.
## Erstellte Dateien
### /legal/privacy_policy.md
Vollständige Datenschutzerklärung mit:
- Verantwortlicher (Platzhalter für Praxisdaten)
- 4 Verarbeitungszwecke (Dokumentation, Kommunikation, Organisation, KI)
- Datenarten inkl. expliziter Nennung von Gesundheitsdaten (Art. 5 DSG)
- Rechtsgrundlagen DSG + DSGVO
- Speicherorte (lokal + Supabase + OpenAI API)
- Auftragsverarbeiter: OpenAI (USA, SCCs), Supabase (EU-Hosting, USA-Sitz)
- Drittlandübertragung dokumentiert
- Betroffenenrechte DSG + DSGVO
- Beschwerderecht (EDÖB + EU-Aufsicht)
- Kontaktstelle
### /legal/ai_consent.md
KI-Einwilligungserklärung mit:
- Erklärung aller 4 KI-Einsatzgebiete (Transkription, KG, Interaktion, Textprüfung)
- Konkrete Angabe der übermittelten Daten pro Funktion
- Benennung des Anbieters (OpenAI) und der Modelle
- Drittlandhinweis (USA, SCCs)
- Klare Abgrenzung: Was KI NICHT entscheidet (keine Diagnosen, keine Therapie)
- Ärztliche Verantwortung explizit festgehalten
- Widerrufsrecht mit konkreten Folgen
- Dokumentationspflicht
- Unterschriftenfelder (Einwilligung + Widerruf)
## Betroffene Dateien
| Datei | Aktion |
|-------|--------|
| /legal/privacy_policy.md | NEU erstellt |
| /legal/ai_consent.md | NEU erstellt |
## Datengrundlage
Alle Aussagen basieren auf dem tatsächlichen Code-Stand:
- OpenAI API-Nutzung: Transkription (gpt-4o-mini-transcribe), Text (gpt-5.2/5-mini/5-nano)
- Supabase Cloud-Sync (eu-central-1)
- Lokale Datenspeicherung (JSON, SQLite)
- Implementierte Sicherheitsmassnahmen aus STEP 4.x und 6
## Offene Punkte
1. **Verantwortlicher:** Platzhalter muss mit echten Praxisdaten ausgefüllt werden
2. **Juristische Prüfung:** Beide Dokumente müssen vor Produktiveinsatz von
einer rechtskundigen Person geprüft werden
3. **AV-Vertrag OpenAI:** DPA/AVV mit OpenAI muss geprüft/abgeschlossen werden
4. **AV-Vertrag Supabase:** DPA/AVV mit Supabase muss geprüft/abgeschlossen werden
5. **Einwilligungsformular:** Muss in druckbare Form gebracht werden (PDF/Papier)
6. **Kantonale Besonderheiten:** Aufbewahrungsfristen variieren je nach Kanton
## Risiken
- Ohne juristische Prüfung sind die Texte nicht rechtsverbindlich
- AV-Verträge mit OpenAI und Supabase fehlen noch (RED im Audit)
- Drittlandübertragung USA ist datenschutzrechtlich sensibel

View File

@@ -0,0 +1,233 @@
# STEP 9 Backup, Recovery & Löschkonzept
## Ziel
Sicherstellung von Datenverlustminimierung, Wiederherstellbarkeit
und Erfüllung der DSG-Löschpflichten.
---
## 1. Datenübersicht
### 1.1 Medizinische / Personenbezogene Daten
| Datei / Speicher | Format | Inhalt | Sensibilität |
|---|---|---|---|
| `kg_diktat_user_profile.json` | JSON | Arztname, Fachgebiet, Passwort-Hash, TOTP-Secret | HOCH |
| `kg_diktat_ablage/KG/` | Dateien | Krankengeschichten | HOCH |
| `kg_diktat_ablage/Briefe/` | Dateien | Arztbriefe | HOCH |
| `kg_diktat_ablage/Rezepte/` | Dateien | Rezepte | HOCH |
| `kg_diktat_ablage/Kostengutsprachen/` | Dateien | Kostengutsprachen | HOCH |
| `kg_diktat_ablage/Diktat/` | Dateien | Diktattexte | HOCH |
| `kg_diktat_notes.json` | JSON | Notizen (ev. Patientenbezug) | MITTEL |
| `kg_diktat_todos.json` | JSON | Aufgaben (ev. Patientenbezug) | MITTEL |
| `kg_diktat_todo_inbox.json` | JSON | Eingehende Aufgaben | MITTEL |
| `kg_diktat_medwork_contacts.json` | JSON | Praxiskontakte | MITTEL |
| `aza_email_contacts.json` | JSON | E-Mail-Kontakte | MITTEL |
| `aza_medwork_messages.json` | JSON | Nachrichten | MITTEL |
| `workforce_planner.db` | SQLite | Mitarbeiter, Abwesenheiten, Audit-Log | MITTEL |
### 1.2 Konfigurationsdaten (nicht personenbezogen)
| Datei | Inhalt |
|---|---|
| `kg_diktat_config.txt` | Grundeinstellungen |
| `kg_diktat_signature.txt` | Arzt-Signatur |
| `kg_diktat_korrekturen.json` | Auto-Korrekturen |
| `kg_diktat_textbloecke.json` | Textbausteine |
| `kg_diktat_autotext.json` | Autotext-Vorlagen |
| `kg_diktat_soap_presets.json` | SOAP-Profile |
| `kg_diktat_brief_presets.json` | Brief-Profile |
| `aza_email_config.json` | E-Mail-Konfiguration (ohne Passwort) |
| Diverse `*_window.txt` | Fensterpositionen / UI-State |
### 1.3 Cloud-Daten
| Dienst | Daten | Speicherort |
|---|---|---|
| Supabase | Synchronisierte Praxisdaten | AWS eu-central-1 |
| OpenAI API | Keine persistente Speicherung (API-Modus, max. 30 Tage) | USA |
---
## 2. Backup-Konzept
### 2.1 Implementierung
Neues Skript: **`aza_backup.py`**
```
python aza_backup.py backup # Backup erstellen
python aza_backup.py list # Backups auflisten
python aza_backup.py verify <f> # Integrität prüfen
python aza_backup.py restore <f> # Wiederherstellen
python aza_backup.py cleanup # Alte Backups entfernen
```
### 2.2 Was wird gesichert
- Alle medizinischen JSON-Dateien (17 Dateien)
- Alle Konfigurationsdateien (12 Dateien)
- Alle UI-State-Dateien (11 Dateien)
- Komplettes Ablage-Verzeichnis (KG, Briefe, Rezepte, etc.)
- Lernmodus-Export
- Workforce-Planner-Datenbank (SQLite)
### 2.3 Backup-Parameter
| Parameter | Wert | Konfiguration |
|---|---|---|
| Format | ZIP (Deflate, Level 9) | Fest |
| Intervall | Täglich empfohlen | Manuell oder Cron/Task Scheduler |
| Aufbewahrung | 90 Tage (Standard) | `AZA_BACKUP_KEEP_DAYS` |
| Zielverzeichnis | `./backups/` | `AZA_BACKUP_DIR` |
| Integrität | SHA-256 pro Datei + Manifest | Automatisch |
| Benennung | `aza_backup_YYYY-MM-DD_HH-MM-SS.zip` | Automatisch |
### 2.4 Verschlüsselung
- **Transport:** ZIP-Dateien können auf verschlüsseltem Medium gespeichert werden
- **Empfehlung:** Backup-Zielverzeichnis auf BitLocker-verschlüsseltem
Laufwerk oder verschlüsseltem NAS ablegen
- **ZIP-eigene Verschlüsselung:** Nicht implementiert (Python-zipfile
unterstützt kein starkes AES; Laufwerksverschlüsselung wird empfohlen)
### 2.5 Offsite-Kopie
- Backup-Verzeichnis (`AZA_BACKUP_DIR`) kann auf externes Medium
oder Netzlaufwerk zeigen
- Empfohlen: Regelmässige Kopie auf externes verschlüsseltes Medium
- Keine automatische Cloud-Sicherung implementiert
### 2.6 Automatisierung (Windows Task Scheduler)
```
schtasks /create /tn "AZA_Backup" /tr "python C:\...\aza_backup.py backup" /sc daily /st 22:00
```
---
## 3. Recovery-Konzept
### 3.1 Recovery Point Objective (RPO)
| Szenario | RPO |
|---|---|
| Tägliches Backup | Max. 24 Stunden Datenverlust |
| Stündliches Backup (optional) | Max. 1 Stunde |
### 3.2 Recovery Time Objective (RTO)
| Szenario | RTO |
|---|---|
| Einzelne Datei | < 5 Minuten |
| Komplettes System | < 30 Minuten |
### 3.3 Restore-Anleitung
#### Schritt 1: Verfügbare Backups anzeigen
```
python aza_backup.py list
```
#### Schritt 2: Backup-Integrität prüfen
```
python aza_backup.py verify backups/aza_backup_YYYY-MM-DD_HH-MM-SS.zip
```
#### Schritt 3: Dry-Run (was wird wiederhergestellt?)
```
python aza_backup.py restore backups/aza_backup_YYYY-MM-DD_HH-MM-SS.zip --dry-run
```
#### Schritt 4: Tatsächliche Wiederherstellung
```
python aza_backup.py restore backups/aza_backup_YYYY-MM-DD_HH-MM-SS.zip
```
**Sicherheitsmechanismus:** Vor dem Restore wird automatisch eine
Pre-Restore-Sicherung der aktuellen Daten erstellt (in `backups/.pre_restore_*/`),
sodass der Restore rückgängig gemacht werden kann.
### 3.4 Test-Ergebnisse (22.02.2026)
| Test | Ergebnis |
|---|---|
| Backup erstellen | PASS 44 Dateien, 0.06 MB |
| Backup verifizieren (SHA-256) | PASS alle Checksummen korrekt |
| Restore Dry-Run | PASS 44 Dateien korrekt aufgelistet |
| Backup auflisten | PASS Datum, Grösse, Name korrekt |
| Löschung Dry-Run | PASS Warnung zu Backups korrekt |
---
## 4. Löschkonzept
### 4.1 Löschfristen
| Datenkategorie | Aufbewahrungsfrist | Rechtsgrundlage |
|---|---|---|
| Krankengeschichten | 1020 Jahre (kantonal) | Kantonale Gesundheitsgesetze |
| Arztbriefe | 1020 Jahre | Kantonale Gesundheitsgesetze |
| Rezepte | 10 Jahre | OR Art. 958f |
| Mitarbeiterdaten | Anstellungsdauer + 5 Jahre | OR Art. 128 |
| E-Mail-Kontakte | Bis Löschung durch Benutzer | DSG Art. 6 |
| Backups | 90 Tage (konfigurierbar) | Intern |
### 4.2 Technische Umsetzung
#### Automatische Backup-Bereinigung
```
python aza_backup.py cleanup
```
Entfernt Backups älter als `AZA_BACKUP_KEEP_DAYS` (Standard: 90 Tage).
#### Patientendaten löschen (Recht auf Vergessenwerden)
```
# Dry-Run (nur prüfen, was gelöscht wird)
python aza_backup.py delete-patient "Nachname Vorname"
# Tatsächliche Löschung
python aza_backup.py delete-patient "Nachname Vorname" --execute
```
### 4.3 Lösch-Workflow
1. **Antrag:** Patient stellt Löschanfrage (schriftlich empfohlen)
2. **Prüfung:** Arzt prüft, ob gesetzliche Aufbewahrungspflicht besteht
3. **Dry-Run:** `delete-patient --dry-run` zeigt betroffene Dateien
4. **Dokumentation:** Löschanfrage und Ergebnis im Audit-Log festhalten
5. **Ausführung:** `delete-patient --execute`
6. **Backups:** Bestehende Backups enthalten noch Daten nach Ablauf
der Aufbewahrungsfrist (90 Tage) werden diese automatisch entfernt
7. **Cloud:** Supabase-Daten manuell löschen (aktuell kein API-Endpunkt)
### 4.4 Einschränkungen
- Löschung in bestehenden Backups nur durch Warten auf Ablauf
oder manuelles Löschen der betroffenen Backups
- Supabase-Cloud-Daten müssen manuell gelöscht werden
- OpenAI-API-Daten werden gemäss OpenAI nach max. 30 Tagen gelöscht
- Namensbasierte Suche funktioniert nur bei Dateinamen / JSON-Inhalt
mit Patientenname
---
## 5. Geänderte / Neue Dateien
| Datei | Aktion |
|---|---|
| `aza_backup.py` | NEU Backup, Verify, Restore, Cleanup, Löschung |
| `backups/` | NEU Backup-Verzeichnis (automatisch erstellt) |
---
## 6. Risiken
| Risiko | Bewertung | Massnahme |
|---|---|---|
| Kein automatischer Backup-Schedule | MITTEL | Task Scheduler einrichten |
| ZIP nicht AES-verschlüsselt | MITTEL | Laufwerksverschlüsselung nutzen |
| Keine Offsite-Kopie konfiguriert | HOCH | `AZA_BACKUP_DIR` auf NAS setzen |
| Supabase-Löschung manuell | MITTEL | API-Endpunkt implementieren |
| Namensbasierte Löschung unvollständig | NIEDRIG | Erweiterte Suche implementieren |
| Kein inkrementelles Backup | NIEDRIG | Bei Datenwachstum nachrüsten |

View File

@@ -0,0 +1,89 @@
# HIN Technische Referenz Quellensammlung
## Status: REFERENZDATEN VORHANDEN
Offizielle PDFs sind nicht frei downloadbar. Stattdessen wurden alle
öffentlich verfügbaren technischen Informationen von HIN-Quellen extrahiert
und in folgenden Dateien zusammengefasst:
- hin_architektur.md → Vollständige technische Referenz (Architektur, PKI, VPN, Auth, Secure Mail)
- hin_quellen.md → Quellenverzeichnis mit allen Original-URLs
---
## 1. Öffentlich verfügbare technische Quellen
### Sicherheitsarchitektur / Netzwerk / SSHN
- **SSHN (Secure Swiss Health Network):** https://support.hin.ch/de/thema/sshn.cfm
- SCION-Technologie, redundante Transportwege, DDoS-Schutz
- Any-to-any Verschlüsselung, zertifikatsbasierte Auth (72h Gültigkeit)
### PKI / Zertifikate
- **HIN Sign (eSigning-Standard):** https://certifaction.com/hin-sign-esigning-standard-for-swiss-healthcare-sector/
- PKI-basierte Zertifikatsverwaltung
- HIN eID-basiertes SSO und Signatur
### VPN / Access Gateway
- **HIN AGW Benutzerhandbuch (v3.1.65):** https://cdn.hin.ch/agw/manual/DE/
- Konfiguration, SSL, Cluster, Monitoring, Administration
- **HIN Gateway (Stargate):** https://support.hin.ch/de/service/hin-gateway.cfm
- Cloud-native Microservice-Architektur, RESTful-APIs
- Self-Sovereign Identity (SSI), Data Mesh
### Authentifizierung
- **HIN Identität / eID:** https://www.hin.ch/de/services/hin-identitaet.cfm
- Elektronische Identitäten mit Zwei-Faktor-Authentisierung
- Single Sign-on für EPD und geschützte Anwendungen
### Secure Mail
- **Was ist Secure Mail:** https://support.hin.ch/de/service/hin-mail-und-mobile/was-ist-secure-mail.cfm
- S/MIME-Verschlüsselung, State-of-the-Art-Standards
- **HIN Mail Global:** https://support.hin.ch/de/thema/hin-mail-global-en/
- Verschlüsselter Versand an externe Empfänger
- SMS-Code-Verifizierung, 30 Tage Link-Gültigkeit
### Publikationen (Geschäftsberichte, Broschüren)
- https://www.hin.ch/de/ueber-hin/unternehmen/publikationen.cfm
### Externe Analyse
- **MSXFaq HIN Mail Analyse:** https://msxfaq.de/signcrypt/hin-mail.htm
- Detaillierte technische Analyse der HIN Mail Architektur
---
## 2. Vorbereitete Support-Anfrage an HIN
**An:** support@hin.ch
**Betreff:** Anfrage technische Sicherheits- und Architekturdokumentation
**Text:**
Sehr geehrte Damen und Herren,
im Rahmen eines Sicherheits- und Compliance-Projekts im Gesundheitswesen
benötigen wir Ihre offizielle technische Dokumentation zu folgenden Bereichen:
- Sicherheitsarchitektur (Gesamtübersicht)
- PKI / Zertifikatsinfrastruktur
- VPN / Netzwerkarchitektur (inkl. SSHN/SCION)
- Authentifizierung (eID, 2FA, SSO)
- Secure Mail (Verschlüsselung, S/MIME)
Bitte senden Sie mir die entsprechenden Dokumente (Whitepapers,
technische Spezifikationen, Architekturdiagramme) oder teilen Sie mir mit,
wo diese heruntergeladen werden können.
Vielen Dank im Voraus.
Mit freundlichen Grüssen,
[Name / Organisation eintragen]
---
## 3. Erhaltene Dokumente (hier eintragen wenn vorhanden)
- [ ] hin_architektur.pdf
- [ ] hin_pki.pdf
- [ ] hin_vpn.pdf
- [ ] hin_auth.pdf
- [ ] hin_secure_mail.pdf

View File

@@ -0,0 +1,202 @@
# HIN Sicherheitsarchitektur Technische Referenz
# Quelle: Öffentlich verfügbare HIN-Dokumentation (Stand Feb 2026)
---
## 1. Überblick
HIN (Health Info Net AG) wurde 1996 auf Initiative der FMH gegründet.
Über 90% der Akteure des Schweizer Gesundheitswesens nutzen HIN.
Ca. 14.500 Einzelabonnenten + 350 Institutionen.
Hauptprodukte:
- HIN Mail (verschlüsselte E-Mail)
- HIN Gateway (Stargate) Organisationsanbindung
- HIN Access Gateway (AGW) VPN/Netzwerkzugang
- HIN Identität (eID) Authentifizierung
- SSHN (Secure Swiss Health Network) SCION-basiertes Netzwerk
- HIN Sign Digitale Signaturen
- HIN Endpoint Security Endgeräteschutz
---
## 2. Netzwerkarchitektur
### 2.1 HIN Vertrauensraum
- Geschlossene Kommunikationsumgebung für das Gesundheitswesen
- Governance durch: HIN, FMH, pharmaSuisse, BAG Cybersicherheit, SWITCH
- Zugang nur für verifizierte Gesundheitsakteure
### 2.2 SSHN (Secure Swiss Health Network) SCION-Technologie
- Basiert auf SCION (ETH Zürich): "Scalability, Control and Isolation on next-generation Networks"
- Redundante Transportwege mit automatischem Fail-over (Sekundenbruchteile)
- Routing ausschliesslich über Schweizer Netze (kein Datenexport)
- Schutz vor DDoS-Attacken
- Any-to-any Verschlüsselung zwischen allen Teilnehmern
- Zertifikatsbasierte Authentifizierung (72h Gültigkeit, Erneuerung nach 18h)
- Erstausgestelltes Zertifikat: 7 Tage Gültigkeit
- Core Member: Swisscom, Sunrise (ISPs mit eigenen autonomen Netzwerken)
- Carrier: Cyberlink, VTX, Everyware (nutzen Core-Member-Netze)
- Auch genutzt von: Swiss Secure Finance Network (SSFN) bei SIX/SNB
- Getestet von: SIX, EDA, Armasuisse
### 2.3 HIN Access Gateway (AGW)
- Virtuelle Appliance (VMware, HyperV, Qemu/Libvirt)
- Aktuelle Version: 3.1.65
- SHA-256 Prüfsummen für Integritätsverifikation
- Funktionen: SSL, Cluster-Management, Monitoring, Administration
### 2.4 HIN Gateway (Stargate) Neue Generation
- Cloud-native Microservice-Architektur
- RESTful-APIs, Open-Source-Komponenten
- Quellcode wird quelloffen sein
- Design orientiert an Gaia-X und European Health Data Space (EHDS)
- Betriebsmodelle: OpenShift, Kubernetes, VMware, Microsoft, QEMU, Hybrid
- EINE Instanz pro Organisation (nicht mandantenfähig bewusste Sicherheitsentscheidung)
- Transport: Wireguard-Protokoll (kein VPN-Tunneling, reiner App-zu-App-Kanal)
- Dezentrale Identitäten (SSI), verteiltes Schlüsselmanagement
- Programmierbare Richtlinien
- Post-Quanten-Kryptografie vorbereitet
Quelle: https://support.hin.ch/de/service/hin-gateway.cfm
---
## 3. PKI / Zertifikatsinfrastruktur
### 3.1 HIN-eigene PKI
- Aussteller: "HIN MGW Issuing CA 2022"
- Zertifikatstyp: Domain-Zertifikate für S/MIME
- CN: "Domain Certificate for <domain>"
- SAN: "domain-confidentiality-authority@<domain>"
- Schlüssel: RSA 4096-bit
- Signatur: SHA256withRSAEncryption
- Gültigkeit: 10 Jahre (Domain-Zertifikate)
### 3.2 SSHN-Zertifikate
- Gültigkeit: 72 Stunden (Standard)
- Erstausstellung: 7 Tage
- Erneuerung: 18h nach Installation des aktuellen Zertifikats
- CSR-Erstellung gemäss Anapaya-Dokumentation
- Einreichung an: certificate-hvr@hin.ch
### 3.3 Zertifikatsverteilung
- HIN-Backend stellt Domain-Zertifikate zentral bereit
- Alle HIN-Gateways laden Public Keys vom HIN-Backend herunter
- Geschlossenes System: Zertifikate nicht extern verfügbar
- Bei Installation: Gateway fordert Zertifikat bei HIN-PKI an
Quelle: https://msxfaq.de/signcrypt/hin-mail.htm
---
## 4. Authentifizierung
### 4.1 HIN Identitätstypen
#### Persönliche eID
- Vergleichbar mit digitalem Ausweisdokument
- Identitätsprüfung via Videoidentifikation
- Berufsqualifikation über Verbände/nationale Register verifiziert
- Zugriff auf EPD möglich
- Höchstes Vertrauenslevel
#### Persönliche eID für Organisationen
- Organisation prüft Identität der Mitarbeitenden
- Nur für HIN Services (nicht HIN-geschützte Anwendungen)
- Erweiterung bestehender lokaler Identitäten (z.B. AD)
#### Team-Identität
- Gemeinsame Nutzung durch mehrere Personen (z.B. MPA-Team)
- Tieferes Vertrauenslevel
- Kein EPD-Zugriff möglich
- Verschlüsselung identisch zur persönlichen eID
### 4.2 Zwei-Faktor-Authentisierung (2FA)
#### HIN Client (Einzelpersonen ohne grosse IT)
- Faktor 1: HIN Passwort
- Faktor 2: Kryptographischer Schlüssel auf dem Gerät
#### HIN Gateway (Organisationen mit IT-Infrastruktur)
- Faktor 1: SMS-Code (mTAN) oder Authentisierungs-App
- Faktor 2: Lokaler Verzeichnisdienst (Active Directory)
#### Mobiler Zugriff
- Faktor 1: SMS-Code (mTAN) oder Authentisierungs-App
- Faktor 2: HIN Login + HIN Passwort
### 4.3 Single Sign-on (SSO)
- Nach HIN-Anmeldung keine erneute Passworteingabe nötig
- Zugriff auf HIN-geschützte Anwendungen
- Zugriff auf EPD-Portale (nur mit persönlicher eID)
Quelle: https://www.hin.ch/de/services/hin-identitaet.cfm
---
## 5. Verschlüsselung / Secure Mail
### 5.1 HIN Mail (intern HIN-zu-HIN)
- S/MIME-Verschlüsselung mit Domain-Zertifikaten
- Automatische Verschlüsselung durch Gateway/Backend
- Gateway prüft Empfänger-Domain gegen HIN-Domainliste
- Ausgehend: Signierung mit eigenem Zertifikat + Verschlüsselung mit Public Key des Empfängers
- Eingehend: Signaturprüfung + Entschlüsselung mit eigenem Private Key
- Header "X-HIN-Encrypted" markiert verschlüsselte Mails
- Transport: SMTP über Internet (MX-Record-Auflösung)
- TLS optional (nicht erzwungen, daher S/MIME als primärer Schutz)
### 5.2 HIN Mail Global (extern an Nicht-HIN-Teilnehmer)
- Betreff muss "(Confidential)" enthalten
- Mail wird auf HIN-Webserver bereitgestellt
- Empfänger erhält Benachrichtigung mit HTML-Anhang ("Secure-email.html")
- Authentifizierung: SMS-Code an registrierte Mobilnummer
- "Gerät merken" Option verfügbar
- Link-Gültigkeit: 30 Tage
- Basiert auf GINA-Verfahren von SEPPMail
- Betreffzeile bleibt UNVERSCHLÜSSELT
### 5.3 Drei Betriebsmodelle
1. **Gehostetes Postfach** (~380 CHF/Jahr): Webmail oder IMAP4, Backend verschlüsselt
2. **HIN Gateway**: Eigener Mailserver, Gateway verschlüsselt/entschlüsselt automatisch
3. **Webbasiert**: Zugriff via webmail.hin.ch
### 5.4 Technische Details Gateway
- HIN Gateway basiert auf SEPPMail-Appliance (reduzierte Funktion)
- Unterstützt Exchange Online Integration (O365)
- Prüft X-OriginatorOrg und X-MS-Exchange-CrossTenant-Id
- SMTP-Schnittstelle für interne Geräte (Relay)
- IMAP-Zugriff über Zimbra-Plattform (unverändert)
Quellen:
- https://support.hin.ch/de/service/hin-mail-und-mobile/was-ist-secure-mail.cfm
- https://msxfaq.de/signcrypt/hin-mail.htm
---
## 6. Rechtlicher Rahmen
- Art. 321 StGB: Verletzung des Berufsgeheimnisses → Gefängnis oder Busse
- Berufsgeheimnisträger: Ärzte, Apotheker, Rechtsanwälte, Revisoren, Geistliche
- Unverschlüsselte E-Mails mit Patientendaten = Verletzung des Berufsgeheimnisses
- HIN-Zertifizierungen entsprechen dem für EPD geforderten Vertrauenslevel
---
## 7. Zusammenfassung: HIN-Sicherheitsniveau
| Bereich | HIN-Standard |
|--------------------------|--------------------------------------------------|
| Netzwerk | SCION/SSHN, nur Schweizer Netze, DDoS-Schutz |
| Verschlüsselung | S/MIME, RSA 4096-bit, SHA256 |
| PKI | Eigene CA ("HIN MGW Issuing CA 2022") |
| Zertifikate | Domain-Zertifikate, 72h SSHN-Zertifikate |
| Authentifizierung | 2FA (mTAN/App + Passwort/AD/Geräteschlüssel) |
| SSO | Ja, für HIN-geschützte Anwendungen |
| Identitätsprüfung | Videoidentifikation, Berufsregister |
| Transport | Wireguard (Stargate), SMTP+S/MIME (Legacy) |
| Mandantentrennung | 1 Instanz pro Organisation |
| Zukunftssicherheit | Post-Quanten-Kryptografie vorbereitet |
| Quellcode | Open Source (Stargate) |
| Governance | FMH, pharmaSuisse, BAG, SWITCH, HIN |

View File

@@ -0,0 +1,64 @@
# HIN Quellenverzeichnis Alle verwendeten Originalquellen
---
## Offizielle HIN-Quellen (hin.ch / support.hin.ch / cdn.hin.ch)
1. SSHN (Secure Swiss Health Network)
https://support.hin.ch/de/thema/sshn.cfm
2. HIN Identität / eID
https://www.hin.ch/de/services/hin-identitaet.cfm
3. Secure Mail
https://support.hin.ch/de/service/hin-mail-und-mobile/was-ist-secure-mail.cfm
4. HIN Mail Global
https://support.hin.ch/de/thema/hin-mail-global-en/
5. HIN Gateway (Stargate)
https://support.hin.ch/de/service/hin-gateway.cfm
6. HIN AGW Benutzerhandbuch v3.1.65
https://cdn.hin.ch/agw/manual/DE/
7. HIN Gateway Dokumentation (ZIP)
https://download.hin.ch/gw/hin-gateway.zip
8. HIN Publikationen
https://www.hin.ch/de/ueber-hin/unternehmen/publikationen.cfm
9. HIN Kollektivmitgliedschaft mit Gateway
https://www.hin.ch/de/hin-mitgliedschaft/kollektivmitgliedschaft/mit-gateway.cfm
10. HIN Zertifizierungen
https://www.hin.ch/de/ueber-hin/zertifizierungen/uebersicht.cfm
11. HIN Sign
https://www.hin.ch/de/services/hin-sign/hin-sign.cfm
12. HIN Datenschutz
https://www.hin.ch/de/ueber-hin/hin-welt/hin-und-der-datenschutz/hin-und-der-datenschutz.cfm
## Externe technische Analysen
13. MSXFaq HIN Mail im Schweizer Gesundheitswesen (Frank Carius)
https://msxfaq.de/signcrypt/hin-mail.htm
→ Detaillierteste externe Analyse der HIN-Architektur
14. HIN Sign / Certifaction
https://certifaction.com/hin-sign-esigning-standard-for-swiss-healthcare-sector/
15. VSHN HIN Success Story
https://www.vshn.ch/en/success-stories/hin-health-info-net/
## SCION-Technologie
16. Anapaya CSR-Erstellung für SSHN
https://docs.anapaya.net/en/latest/edge/user-guides/crypto-provisioning/#edge-appliance-generate-csr
## Kontakt HIN Support
- E-Mail: support@hin.ch
- Telefon SSHN: 0848 830 740
- Zertifikate SSHN: certificate-hvr@hin.ch