Compare commits
4 Commits
035681ab28
...
0f6dda44b8
Author | SHA1 | Date |
---|---|---|
|
0f6dda44b8 | |
|
b4b5a7ac8f | |
|
a45e064c18 | |
|
ecb4e0fab4 |
|
@ -90,33 +90,38 @@ class User {
|
|||
* @return bool True if login is successful, false otherwise.
|
||||
*/
|
||||
public function login($username, $password) {
|
||||
// get client IP address
|
||||
$ipAddress = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
||||
try {
|
||||
// Get user's IP address
|
||||
require_once __DIR__ . '/../helpers/logs.php';
|
||||
$ipAddress = getUserIP();
|
||||
|
||||
// Record attempt
|
||||
$this->rateLimiter->attempt($username, $ipAddress);
|
||||
// Record attempt
|
||||
$this->rateLimiter->attempt($username, $ipAddress);
|
||||
|
||||
// Check rate limiting first
|
||||
if (!$this->rateLimiter->isAllowed($username, $ipAddress)) {
|
||||
$remainingTime = $this->rateLimiter->getDecayMinutes();
|
||||
throw new Exception("Too many login attempts. Please try again in {$remainingTime} minutes.");
|
||||
// Check rate limiting first
|
||||
if (!$this->rateLimiter->isAllowed($username, $ipAddress)) {
|
||||
$remainingTime = $this->rateLimiter->getDecayMinutes();
|
||||
throw new Exception("Too many login attempts. Please try again in {$remainingTime} minutes.");
|
||||
}
|
||||
|
||||
// Then check credentials
|
||||
$query = $this->db->prepare("SELECT * FROM users WHERE username = :username");
|
||||
$query->bindParam(':username', $username);
|
||||
$query->execute();
|
||||
|
||||
$user = $query->fetch(PDO::FETCH_ASSOC);
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get remaining attempts AFTER this failed attempt
|
||||
$remainingAttempts = $this->rateLimiter->getRemainingAttempts($username, $ipAddress);
|
||||
throw new Exception("Invalid credentials. {$remainingAttempts} attempts remaining.");
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
// Then check credentials
|
||||
$query = $this->db->prepare("SELECT * FROM users WHERE username = :username");
|
||||
$query->bindParam(':username', $username);
|
||||
$query->execute();
|
||||
|
||||
$user = $query->fetch(PDO::FETCH_ASSOC);
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get remaining attempts AFTER this failed attempt
|
||||
$remainingAttempts = $this->rateLimiter->getRemainingAttempts($username, $ipAddress);
|
||||
throw new Exception("Invalid credentials. {$remainingAttempts} attempts remaining.");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__ . '/../helpers/security.php';
|
||||
require_once __DIR__ . '/../helpers/logs.php';
|
||||
|
||||
function applyCsrfMiddleware() {
|
||||
global $dbWeb, $logObject;
|
||||
$security = SecurityHelper::getInstance();
|
||||
|
||||
// Skip CSRF check for GET requests
|
||||
|
@ -11,9 +11,10 @@ function applyCsrfMiddleware() {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Skip CSRF check for initial login attempt
|
||||
// Skip CSRF check for initial login and registration attempts
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' &&
|
||||
isset($_GET['page']) && $_GET['page'] === 'login' &&
|
||||
isset($_GET['page']) &&
|
||||
in_array($_GET['page'], ['login', 'register']) &&
|
||||
!isset($_SESSION['username'])) {
|
||||
return true;
|
||||
}
|
||||
|
@ -23,13 +24,14 @@ function applyCsrfMiddleware() {
|
|||
$token = $_POST['csrf_token'] ?? '';
|
||||
if (!$security->verifyCsrfToken($token)) {
|
||||
// Log CSRF attempt
|
||||
$ipAddress = getUserIP();
|
||||
$logMessage = sprintf(
|
||||
"CSRF attempt detected - IP: %s, Page: %s, User: %s",
|
||||
$_SERVER['REMOTE_ADDR'],
|
||||
$ipAddress,
|
||||
$_GET['page'] ?? 'unknown',
|
||||
$_SESSION['username'] ?? 'anonymous'
|
||||
);
|
||||
$logObject->insertLog(0, $logMessage);
|
||||
$logObject->insertLog(0, $logMessage, 'system');
|
||||
|
||||
// Return error message
|
||||
http_response_code(403);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__ . '/../classes/ratelimiter.php';
|
||||
require_once __DIR__ . '/../helpers/logs.php';
|
||||
|
||||
/**
|
||||
* Rate limit middleware for page requests
|
||||
|
@ -14,7 +15,7 @@ function checkRateLimit($database, $endpoint, $userId = null) {
|
|||
global $app_root;
|
||||
$isTest = defined('PHPUNIT_RUNNING');
|
||||
$rateLimiter = new RateLimiter($database);
|
||||
$ipAddress = $_SERVER['REMOTE_ADDR'];
|
||||
$ipAddress = getUserIP();
|
||||
|
||||
// Check if request is allowed
|
||||
if (!$rateLimiter->isPageRequestAllowed($ipAddress, $endpoint, $userId)) {
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
if ($config['registration_enabled'] == true) {
|
||||
|
||||
try {
|
||||
|
||||
// connect to database
|
||||
$dbWeb = connectDB($config)['db'];
|
||||
global $dbWeb, $logObject, $userObject;
|
||||
|
||||
if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
|
||||
|
||||
|
@ -42,8 +40,9 @@ if ($config['registration_enabled'] == true) {
|
|||
]
|
||||
];
|
||||
|
||||
$username = $_POST['username'] ?? 'unknown';
|
||||
|
||||
if ($validator->validate($rules)) {
|
||||
$username = $_POST['username'];
|
||||
$password = $_POST['password'];
|
||||
|
||||
// registering
|
||||
|
@ -51,22 +50,29 @@ if ($config['registration_enabled'] == true) {
|
|||
|
||||
// redirect to login
|
||||
if ($result === true) {
|
||||
// Get the new user's ID for logging
|
||||
$user_id = $userObject->getUserId($username)[0]['id'];
|
||||
$logObject->insertLog($user_id, "Registration: New user \"$username\" registered successfully. IP: $user_IP", 'user');
|
||||
Feedback::flash('NOTICE', 'DEFAULT', "Registration successful. You can log in now.");
|
||||
header('Location: ' . htmlspecialchars($app_root));
|
||||
exit();
|
||||
// registration fail, redirect to login
|
||||
} else {
|
||||
$logObject->insertLog(0, "Registration: Failed registration attempt for user \"$username\". IP: $user_IP. Reason: $result", 'system');
|
||||
Feedback::flash('ERROR', 'DEFAULT', "Registration failed. $result");
|
||||
header('Location: ' . htmlspecialchars($app_root));
|
||||
exit();
|
||||
}
|
||||
} else {
|
||||
Feedback::flash('ERROR', 'DEFAULT', $validator->getFirstError());
|
||||
$error = $validator->getFirstError();
|
||||
$logObject->insertLog(0, "Registration: Failed validation for user \"" . ($username ?? 'unknown') . "\". IP: $user_IP. Reason: $error", 'system');
|
||||
Feedback::flash('ERROR', 'DEFAULT', $error);
|
||||
header('Location: ' . htmlspecialchars($app_root . '?page=register'));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$logObject->insertLog(0, "Registration: System error. IP: $user_IP. Error: " . $e->getMessage(), 'system');
|
||||
Feedback::flash('ERROR', 'DEFAULT', $e->getMessage());
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
<form method="POST" action="<?= htmlspecialchars($app_root) ?>?page=login">
|
||||
<?php include 'csrf_token.php'; ?>
|
||||
<div class="form-group mb-3">
|
||||
<input type="text" class="form-control w-50 mx-auto" name="username" placeholder="Username".
|
||||
pattern="[a-zA-Z0-9_-]{3,20}" title="3-20 characters, letters, numbers, - and _"
|
||||
<input type="text" class="form-control w-50 mx-auto" name="username" placeholder="Username"
|
||||
pattern="[A-Za-z0-9_\-]{3,20}" title="3-20 characters, letters, numbers, - and _"
|
||||
required autofocus />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<input type="password" class="form-control w-50 mx-auto" name="password" placeholder="Password".
|
||||
<input type="password" class="form-control w-50 mx-auto" name="password" placeholder="Password"
|
||||
pattern=".{2,}" title="Eight or more characters"
|
||||
required />
|
||||
</div>
|
||||
|
|
|
@ -4,12 +4,22 @@
|
|||
<div class="card-body">
|
||||
<p class="card-text">Enter credentials for registration:</p>
|
||||
<form method="POST" action="<?= htmlspecialchars($app_root) ?>?page=register">
|
||||
<input type="text" name="username" placeholder="Username" required autofocus />
|
||||
<br />
|
||||
<input type="password" name="password" placeholder="Password" required />
|
||||
<br />
|
||||
<input type="password" name="confirm_password" placeholder="Confirm password" required />
|
||||
<br /> <br />
|
||||
<?php include 'csrf_token.php'; ?>
|
||||
<div class="form-group mb-3">
|
||||
<input type="text" class="form-control w-50 mx-auto" name="username" placeholder="Username"
|
||||
pattern="[A-Za-z0-9_\-]{3,20}" title="3-20 characters, letters, numbers, - and _"
|
||||
required autofocus />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<input type="password" class="form-control w-50 mx-auto" name="password" placeholder="Password"
|
||||
pattern=".{8,}" title="Eight or more characters"
|
||||
required />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<input type="password" class="form-control w-50 mx-auto" name="confirm_password" placeholder="Confirm password"
|
||||
pattern=".{8,}" title="Eight or more characters"
|
||||
required />
|
||||
</div>
|
||||
<input type="submit" class="btn btn-primary" value="Register" />
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -24,14 +24,6 @@ require '../app/includes/sanitize.php';
|
|||
session_name('jilo');
|
||||
session_start();
|
||||
|
||||
// Initialize security middleware
|
||||
require_once '../app/includes/csrf_middleware.php';
|
||||
require_once '../app/helpers/security.php';
|
||||
$security = SecurityHelper::getInstance();
|
||||
|
||||
// Verify CSRF token for POST requests
|
||||
applyCsrfMiddleware();
|
||||
|
||||
// Initialize feedback message system
|
||||
require_once '../app/classes/feedback.php';
|
||||
$system_messages = [];
|
||||
|
@ -137,6 +129,14 @@ include '../app/helpers/logs.php';
|
|||
$logObject = new Log($dbWeb);
|
||||
$user_IP = getUserIP();
|
||||
|
||||
// Initialize security middleware
|
||||
require_once '../app/includes/csrf_middleware.php';
|
||||
require_once '../app/helpers/security.php';
|
||||
$security = SecurityHelper::getInstance();
|
||||
|
||||
// Verify CSRF token for POST requests
|
||||
applyCsrfMiddleware();
|
||||
|
||||
// init rate limiter
|
||||
require '../app/classes/ratelimiter.php';
|
||||
|
||||
|
|
Loading…
Reference in New Issue