From 44ad71a11686ae6e25e00cf5e277e5e5c6ab619b Mon Sep 17 00:00:00 2001 From: Lain Iwakura Date: Mon, 16 Jun 2025 01:16:48 +0300 Subject: [PATCH] yet another FVKING security update --- main/db.sql | 11 ++++++++--- main/login.php | 36 +++++++++++++++++++++++++++--------- main/register.php | 21 +++++++++++++++------ 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/main/db.sql b/main/db.sql index 65bcf83..9482ed4 100644 --- a/main/db.sql +++ b/main/db.sql @@ -4,7 +4,8 @@ CREATE TABLE messages ( message TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, signature TEXT, - is_encrypted BOOLEAN DEFAULT FALSE + is_encrypted BOOLEAN DEFAULT FALSE, + INDEX idx_created_at (created_at) ); CREATE TABLE users ( @@ -13,11 +14,15 @@ CREATE TABLE users ( password VARCHAR(255) NOT NULL, pgp_key TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - is_moderator TINYINT(1) NOT NULL DEFAULT 0 + is_moderator TINYINT(1) NOT NULL DEFAULT 0, + login_attempts INT NOT NULL DEFAULT 0, + last_attempt TIMESTAMP NULL, + INDEX idx_username (username) ); CREATE TABLE registrations ( id INT AUTO_INCREMENT PRIMARY KEY, ip VARCHAR(45) NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_ip_created (ip, created_at) ); \ No newline at end of file diff --git a/main/login.php b/main/login.php index 68f271e..bb95d8b 100644 --- a/main/login.php +++ b/main/login.php @@ -1,9 +1,12 @@ setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING); - $password = $_POST['password'] ?? ''; + $password = filter_input(INPUT_POST, 'password', FILTER_SANITIZE_STRING); + if ($username && $password) { - $stmt = $db->prepare('SELECT id, password, is_moderator FROM users WHERE username = ?'); + $stmt = $db->prepare('SELECT id, password, is_moderator, login_attempts, last_attempt FROM users WHERE username = ?'); $stmt->execute([$username]); $user = $stmt->fetch(PDO::FETCH_ASSOC); - if ($user && password_verify($password, $user['password'])) { - $_SESSION['user_id'] = $user['id']; - $_SESSION['username'] = $username; - $_SESSION['is_moderator'] = $user['is_moderator']; - header('Location: index.php'); - exit; + + if ($user) { + if ($user['login_attempts'] >= 5 && strtotime($user['last_attempt']) > strtotime('-15 minutes')) { + $error = 'Too many login attempts. Please try again later.'; + } else if (password_verify($password, $user['password'])) { + session_regenerate_id(true); + $_SESSION['user_id'] = $user['id']; + $_SESSION['username'] = $username; + $_SESSION['is_moderator'] = $user['is_moderator']; + + $stmt = $db->prepare('UPDATE users SET login_attempts = 0, last_attempt = NOW() WHERE id = ?'); + $stmt->execute([$user['id']]); + + header('Location: index.php'); + exit; + } else { + $stmt = $db->prepare('UPDATE users SET login_attempts = login_attempts + 1, last_attempt = NOW() WHERE id = ?'); + $stmt->execute([$user['id']]); + $error = 'Invalid username or password'; + } } else { $error = 'Invalid username or password'; } diff --git a/main/register.php b/main/register.php index 060ca94..ce5ee64 100644 --- a/main/register.php +++ b/main/register.php @@ -1,9 +1,12 @@ 50 || strlen($password) < 8) { + if (strlen($username) > 50 || strlen($password) < 8 || !preg_match('/^[a-zA-Z0-9_]+$/', $username)) { $error = 'Invalid data'; + } else if (strlen($pgp_key) > 4096) { + $error = 'PGP key is too long'; } else { $stmt = $db->prepare('SELECT COUNT(*) FROM registrations WHERE ip = ? AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)'); $stmt->execute([$ip]); @@ -34,8 +39,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $error = 'Registration limit exceeded for your IP'; } else { try { - $stmt = $db->prepare('INSERT INTO users (username, password, pgp_key) VALUES (?, ?, ?)'); - $stmt->execute([$username, password_hash($password, PASSWORD_DEFAULT), $pgp_key]); + $stmt = $db->prepare('INSERT INTO users (username, password, pgp_key, login_attempts, last_attempt) VALUES (?, ?, ?, 0, NOW())'); + $stmt->execute([ + $username, + password_hash($password, PASSWORD_DEFAULT, ['cost' => 12]), + $pgp_key + ]); $stmt = $db->prepare('INSERT INTO registrations (ip) VALUES (?)'); $stmt->execute([$ip]);