Files
aza/AzA march 2026 - Kopie (3)/security/handovers/STEP_6_2FA.md
2026-03-30 07:59:11 +02:00

217 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.