diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62c62f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Dev-/Test-Abhängigkeiten (Laufzeit braucht KEIN composer) +/vendor/ +composer.lock +.phpunit.result.cache +.phpunit.cache/ + +# Updater-Laufzeitdaten +/updater/storage/.version +/updater/storage/.maintenance +/updater/storage/.update-progress +/updater/storage/.update.zip +/updater/storage/.update-staging/ +/updater/storage/.migrations-lock +/updater/storage/updater-settings.json diff --git a/forgot_password.php b/forgot_password.php index aff3b62..ef5cc38 100644 --- a/forgot_password.php +++ b/forgot_password.php @@ -24,9 +24,16 @@ $success = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $email = trim($_POST['email'] ?? ''); - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + // Einfacher Throttle: max. 3 Anfragen pro 15 Minuten je Session (gegen Spam) + $now = time(); + $rl = array_values(array_filter($_SESSION['pwreset_times'] ?? [], fn($t) => ($now - $t) < 900)); + if (count($rl) >= 3) { + $error = 'Zu viele Anfragen. Bitte warten Sie einige Minuten.'; + } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $error = __('error_email_invalid'); } else { + $rl[] = $now; + $_SESSION['pwreset_times'] = $rl; $user = $db->fetchOne("SELECT * FROM users WHERE email = ? AND is_active = 1 AND password_hash IS NOT NULL", [$email]); // Always show success (don't reveal whether email exists) diff --git a/includes/Auth.php b/includes/Auth.php index 22764e1..2c62e79 100644 --- a/includes/Auth.php +++ b/includes/Auth.php @@ -1,6 +1,7 @@ consumeBackupCode($user, $code)) { $ok = true; $this->writeAuditLog($user['id'], 'user_login_backup_code', 'user', $user['id'], 'Login per Recovery-Code'); @@ -143,7 +145,7 @@ class Auth { $hashes = array_map(function ($c) { return hash('sha256', $c); }, $codes); $this->db->query( "UPDATE users SET totp_secret = ?, totp_enabled = 1, totp_backup_codes = ? WHERE id = ?", - [$secret, json_encode($hashes), $userId] + [Crypto::encrypt($secret), json_encode($hashes), $userId] ); $this->writeAuditLog($userId, 'totp_enabled', 'user', $userId, '2FA aktiviert'); return $codes;