Files
aza/AzA march 2026 - Kopie (6)/security/handovers/STEP_4_2_HASHING.md
2026-04-16 13:32:32 +02:00

100 lines
3.3 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 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).