added brute force protection

This commit is contained in:
Ryan
2025-03-22 05:44:56 -04:00
committed by GitHub
parent 2e55f5f4d7
commit edb8ff476a
4 changed files with 94 additions and 29 deletions

View File

@@ -4,7 +4,45 @@ header('Content-Type: application/json');
$usersFile = USERS_DIR . USERS_FILE;
// Function to authenticate user
// --- Brute Force Protection Settings ---
$maxAttempts = 5;
$lockoutTime = 30 * 60; // 30 minutes in seconds
$attemptsFile = USERS_DIR . 'failed_logins.json'; // JSON file for tracking failed login attempts
$failedLogFile = USERS_DIR . 'failed_login.log'; // Plain text log for fail2ban
// Load failed attempts data from file.
function loadFailedAttempts($file) {
if (file_exists($file)) {
$data = json_decode(file_get_contents($file), true);
if (is_array($data)) {
return $data;
}
}
return [];
}
// Save failed attempts data to file.
function saveFailedAttempts($file, $data) {
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT));
}
// Get current IP address.
$ip = $_SERVER['REMOTE_ADDR'];
$currentTime = time();
// Load failed attempts.
$failedAttempts = loadFailedAttempts($attemptsFile);
// Check if this IP is currently locked out.
if (isset($failedAttempts[$ip])) {
$attemptData = $failedAttempts[$ip];
if ($attemptData['count'] >= $maxAttempts && ($currentTime - $attemptData['last_attempt']) < $lockoutTime) {
echo json_encode(["error" => "Too many failed login attempts. Please try again later."]);
exit;
}
}
// --- Authentication Function ---
function authenticate($username, $password)
{
global $usersFile;
@@ -23,7 +61,7 @@ function authenticate($username, $password)
return false;
}
// Get JSON input
// Get JSON input.
$data = json_decode(file_get_contents("php://input"), true);
$username = trim($data["username"] ?? "");
$password = trim($data["password"] ?? "");
@@ -40,10 +78,15 @@ if (!preg_match('/^[A-Za-z0-9_\- ]+$/', $username)) {
exit;
}
// Authenticate user
// Attempt to authenticate the user.
$userRole = authenticate($username, $password);
if ($userRole !== false) {
// Regenerate session ID to mitigate session fixation attacks
// On successful login, reset failed attempts for this IP.
if (isset($failedAttempts[$ip])) {
unset($failedAttempts[$ip]);
saveFailedAttempts($attemptsFile, $failedAttempts);
}
// Regenerate session ID to mitigate session fixation attacks.
session_regenerate_id(true);
$_SESSION["authenticated"] = true;
$_SESSION["username"] = $username;
@@ -51,5 +94,19 @@ if ($userRole !== false) {
echo json_encode(["success" => "Login successful", "isAdmin" => $_SESSION["isAdmin"]]);
} else {
// On failed login, update failed attempts.
if (isset($failedAttempts[$ip])) {
$failedAttempts[$ip]['count']++;
$failedAttempts[$ip]['last_attempt'] = $currentTime;
} else {
$failedAttempts[$ip] = ['count' => 1, 'last_attempt' => $currentTime];
}
saveFailedAttempts($attemptsFile, $failedAttempts);
// Log the failed attempt to the plain text log for fail2ban.
$logLine = date('Y-m-d H:i:s') . " - Failed login attempt for username: " . $username . " from IP: " . $ip . PHP_EOL;
file_put_contents($failedLogFile, $logLine, FILE_APPEND);
echo json_encode(["error" => "Invalid credentials"]);
}
?>