Files
aza/AzA march 2026/security/handovers/STEP_6_2FA.md
2026-03-25 22:03:39 +01:00

5.9 KiB
Raw Blame History

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)

{
  "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.