app/totp.php implementiert RFC 6238 selbst statt per Bibliothek: der Algorithmus ist ein HMAC plus eine Truncation, und ein zweiter Faktor ist die letzte Stelle fuer ungepruefte Abhaengigkeiten. Der QR-Code entsteht aus dem ohnehin vorhandenen TCPDF, damit kein externer Dienst das Geheimnis sieht. Beim Login wird die Anmeldung bei aktivem zweitem Faktor nicht abgeschlossen; der Zwischenzustand gewaehrt keinerlei Zugriff und ist byte-identisch zu einem unangemeldeten Aufruf. users.totp_last_step verhindert die Wiederverwendung eines abgefangenen Codes innerhalb seines Gueltigkeitsfensters. Abschalten verlangt Passwort und Code. APP_REQUIRE_2FA_FOR_ADMINS macht den Faktor fuer Platform-Admins verbindlich, per Weiterleitung auf die Einrichtung statt als harte Sperre - sonst koennte der Schalter den einzigen Admin aussperren. Standard aus. check-konto-und-mandantenwechsel erwartete beim Login noch das entfernte Kundenkuerzel-Feld und damit einen direkten Sprung aufs Dashboard; der Check bildet jetzt den tatsaechlichen Weg ueber die Mandantenauswahl ab. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
29 lines
1.3 KiB
SQL
29 lines
1.3 KiB
SQL
-- Zweiter Faktor per TOTP (RFC 6238).
|
|
--
|
|
-- totp_secret haelt das Base32-Geheimnis. Es steht schon vor der Bestaetigung
|
|
-- in der Zeile, damit der eingegebene Code dagegen geprueft werden kann;
|
|
-- scharf ist der zweite Faktor aber erst mit totp_confirmed_at. Wer die
|
|
-- Einrichtung abbricht, sperrt sich damit nicht aus.
|
|
--
|
|
-- totp_last_step merkt sich den zuletzt eingeloesten Zeitschritt. Ohne das
|
|
-- liesse sich ein abgefangener Code innerhalb seines Gueltigkeitsfensters
|
|
-- ein zweites Mal verwenden.
|
|
ALTER TABLE users
|
|
ADD COLUMN totp_secret VARCHAR(64) NULL AFTER password_hash,
|
|
ADD COLUMN totp_confirmed_at DATETIME NULL AFTER totp_secret,
|
|
ADD COLUMN totp_last_step BIGINT NULL AFTER totp_confirmed_at;
|
|
|
|
-- Wiederherstellungscodes fuer den Fall, dass das Telefon verloren geht.
|
|
-- Gespeichert wird nur der Hash: im Klartext sind die Codes genau einmal
|
|
-- sichtbar, direkt nach der Einrichtung.
|
|
CREATE TABLE IF NOT EXISTS totp_recovery_codes (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
user_id INT NOT NULL,
|
|
code_hash VARCHAR(255) NOT NULL,
|
|
used_at DATETIME NULL,
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
KEY idx_totp_recovery_codes_user (user_id, used_at),
|
|
CONSTRAINT fk_totp_recovery_codes_user
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|