diff --git a/intern/login.php b/intern/login.php index 259d08d..64b3ba1 100644 --- a/intern/login.php +++ b/intern/login.php @@ -32,17 +32,19 @@ if (!empty($_POST['email']) && !empty($_POST['passwort'])) { ->execute(['uid' => $user['id']]); // 2FA-Code - $code = random_int(100000, 999999); - $codeHash = hash('sha256', $code); - $expires = date('Y-m-d H:i:s', time() + 300); + $code = random_int(100000, 999999); + $codeHash = hash('sha256', (string)$code); $pdo->prepare(" + -- Ablaufzeit bewusst per NOW() in SQL berechnen: Webserver und + -- DB-Server stehen bei verschiedenen Anbietern und koennen + -- unterschiedliche Zeitzonen haben. verify_2fa.php prueft + -- ebenfalls gegen NOW(), damit beide dieselbe Uhr benutzen. INSERT INTO intern_2fa_codes (user_id, code, expires_at) - VALUES (:uid, :code, :expires) + VALUES (:uid, :code, DATE_ADD(NOW(), INTERVAL 5 MINUTE)) ")->execute([ - 'uid' => $user['id'], - 'code' => $codeHash, - 'expires' => $expires + 'uid' => $user['id'], + 'code' => $codeHash ]); SendMailMessageSilent( diff --git a/intern/verify_2fa.php b/intern/verify_2fa.php index d8728af..98d34f0 100644 --- a/intern/verify_2fa.php +++ b/intern/verify_2fa.php @@ -15,16 +15,23 @@ $error_msg = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['code'])) { - $userId = (int)$_SESSION['2fa_userid']; - $codeHash = hash('sha256', $_POST['code']); + $userId = (int)$_SESSION['2fa_userid']; - // 2FA-Code prüfen + // Aus HTML-Mails kopierte Codes enthalten haeufig Leerzeichen oder + // geschuetzte Leerzeichen. Der Code besteht immer aus sechs Ziffern. + $eingabe = preg_replace('/\D/', '', (string)$_POST['code']); + $codeHash = hash('sha256', $eingabe); + + // Der Ablauf wird in SQL geprueft (NOW()), nicht in PHP: der Webserver + // und der DB-Server stehen bei verschiedenen Anbietern und koennen in + // unterschiedlichen Zeitzonen laufen. Wuerde die Ablaufzeit in PHP + // erzeugt und gegen NOW() verglichen, waere jeder Code sofort + // "abgelaufen". Ablauf und Tippfehler werden getrennt gemeldet. $stmt = $pdo->prepare(" - SELECT id + SELECT id, (expires_at > NOW()) AS noch_gueltig FROM intern_2fa_codes WHERE user_id = :uid AND code = :code - AND expires_at > NOW() LIMIT 1 "); $stmt->execute([ @@ -34,7 +41,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['code'])) { $row = $stmt->fetch(PDO::FETCH_ASSOC); - if ($row) { + if ($row && $row['noch_gueltig']) { // Code löschen (Einmalverwendung) $pdo->prepare("DELETE FROM intern_2fa_codes WHERE user_id = :uid") @@ -79,7 +86,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['code'])) { exit; } - $error_msg = 'Falscher oder abgelaufener Code.'; + $error_msg = $row + ? 'Der Code ist abgelaufen. Bitte melden Sie sich erneut an, damit wir Ihnen einen neuen Code schicken können.' + : 'Der eingegebene Code war nicht korrekt.'; } include("templates/header.inc.php");