Ergebnis einer beauftragten Sicherheitsbegutachtung. Die WebAuthn-
Zeremonie selbst ist nicht angefasst worden - sie war in Ordnung. Alle
Befunde lagen DANEBEN:
Ein zweiter Faktor ist nur so stark wie der schwaechste Weg zum Konto,
und Sitzungen, die aus ihm entstehen, erben seinen Schutz nicht.
KRITISCH
/api/setup/v1/login prueste auf totp_secret - eine Spalte, die kein
Anmeldeweg auswertet - und nicht auf dc_user_credentials. Ein
Administratorpasswort genuegte dort fuer ein setup:install-Token ohne
Hardwarekey. Neu: Konten mit zweitem Faktor abgewiesen, und die
Rollentrennung gilt symmetrisch. Der Docblock behauptete sie seit jeher;
erzwungen hat sie nichts.
HOCH
secondFactorRequired(), accountLockoutSeconds() und lockoutSeconds()
fingen jedes Throwable und fielen auf "kein Faktor" bzw. "nicht
gesperrt" zurueck. Gefangen wurden damit auch Verbindungsabbrueche und
Lock-Timeouts - jeder davon schaltete still fuer alle Konten auf
Passwort-allein. Toleriert werden jetzt nur noch 42S02 und 42S22.
HOCH
Fuenf Aktionen aenderten die Anmeldemittel ohne erneute Bestaetigung.
Eine uebernommene Sitzung konnte sich damit dauerhaft einnisten. Neu:
Authentifizierung aus den letzten zehn Minuten noetig, geprueft an
derselben Stelle, an der auch der Leerlauf sperrt.
WEITER
- Leerlauf 30 statt 120 Minuten, und GESPERRT statt beendet: AAL2 laesst
zur Reaktivierung einen Faktor genuegen. Wer alle 30 Minuten den
Hardwarekey vorzeigen muss, laesst ihn stecken.
- Migration 022: session_epoch. Ein Passwortwechsel beendet die uebrigen
Sitzungen des Kontos, die eigene bleibt.
- Kontosperre wirkt auf der zweiten Stufe; Zaehler gegen unbegrenztes
Raten im Zwischenzustand.
- Drosselung auf login.php (10/60s) und /api/auth/v1/ (30/60s).
- Anmeldefehler ununterscheidbar; die IP-Sperre darf benannt bleiben,
sie sagt nichts ueber ein Konto.
- HSTS, TLS-Zwang VOR allen Routen, CSP. Die CSP traegt wegen 93
Inline-Handlern nicht gegen XSS - das steht so im Kommentar.
- session.use_strict_mode, CSRF-Token bei der Anmeldung verworfen,
Secure-Flag aus app.url statt aus $_SERVER['HTTPS'].
- rpId/expectedOrigin nicht mehr aus dem Host-Header. /api/health meldet
unter checks.webauthn_anchor, ob der Anker steht.
- Notfalltoken laeuft nach 180 Tagen ab, geprueft nach dem Hashvergleich.
- config.example.php ohne echtes Passwort, verify_ssl auf true.
- Serverdaten.txt.bak mitgesperrt, dc_login_attempts raeumt auf.
BELEGT
188 von 188 Testfaellen gruen, darunter drei neue in der Gruppe
"haertung". Die Blockade einer veralteten Sitzung liess sich nicht in
der Suite pruefen - sie verlangt, das Zehn-Minuten-Fenster wirklich
abzuwarten. Dafuer gibt es ein Werkzeug ausserhalb; es belegt, dass der
Formularweg auf den Sperrbildschirm fuehrt, die Regel dabei unveraendert
bleibt, der JSON-Weg reauth_required meldet und das Passwort allein
wieder oeffnet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei Befunde aus der Abnahme auf der Testinstanz.
1. Die Ablehnung eines Softwarekeys erschien als "[object Object]".
Die API verpackt Fehler als { error: { code, message } }; das
JavaScript las "data.message || data.error" und griff damit auf das
OBJEKT zu - ausgerechnet an der Stelle, an der die Begruendung stehen
sollte, warum ein Schluessel abgelehnt wurde. Eine Regel, die ihren
Grund nicht nennt, ist in der Bedienung dasselbe wie ein Defekt.
Derselbe Fehler steckte in login.php. Dort waere er schwerer wiegend:
An der zweiten Stufe ist diese Meldung der einzige Hinweis, warum es
nicht weitergeht. Beide lesen jetzt beide Formen - die verschachtelte
und die flache, die weiterhin vorkommt.
2. Die Textbox fuer die Modellliste stand neben statt unter ihrer
Beschriftung und behielt ihre Eigengroesse. Der umschliessende
form-group fehlte; genau der setzt im Stylesheet display:flex mit
column und laesst das Feld die Breite fuellen. Alle anderen
Textboxen der Oberflaeche haben ihn.
Zusaetzlich docs/HARDWAREKEY.md: Konzept, Beispielcode und Prueflíste
zur gleichwertigen Uebernahme in ein anderes Projekt. Der Schwerpunkt
liegt auf den drei Dingen, die wie eine Pruefung aussehen und keine
sind - cross-platform, response.authenticatorAttachment und ein blosses
x5c -, samt dem Gegentest, ohne den nichts belegt ist.
Kein Eingriff in src/, sql/ oder public/api/ - der Kern ist unveraendert
gegenueber dem Lauf mit 184 von 184 gruenen Testfaellen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>