diff --git a/login.php b/login.php
index 4ac43edd..cba46daf 100644
--- a/login.php
+++ b/login.php
@@ -5,13 +5,28 @@ if(!file_exists('config.php')){
exit;
}
-include("config.php");
-include("functions.php");
+require_once("config.php");
+require_once("functions.php");
+require_once("rfc6238.php");
// IP & User Agent for logging
$ip = strip_tags(mysqli_real_escape_string($mysqli,get_ip()));
$user_agent = strip_tags(mysqli_real_escape_string($mysqli,$_SERVER['HTTP_USER_AGENT']));
+// Block brute force password attacks - check recent failed login attempts for this IP
+// Block access if more than 15 failed login attempts have happened in the last 10 minutes
+$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT(log_id) AS failed_login_count FROM logs WHERE log_ip = '$ip' AND log_type = 'Login' AND log_action = 'Failed' AND log_created_at > (NOW() - INTERVAL 10 MINUTE)"));
+$failed_login_count = $row['failed_login_count'];
+
+if ($failed_login_count >= 15) {
+
+ // Logging
+ mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login', log_action = 'Blocked', log_description = '$ip was blocked access to login due to IP lockout', log_ip = '$ip', log_user_agent = '$user_agent'");
+
+ // Inform user & quit processing page
+ exit("
ITFlow
Your IP address has been blocked due to repeated failed login attempts. Please try again later.
This action has been logged.");
+}
+
// Query Settings for "default" company (as companies are being removed shortly)
$sql_settings = mysqli_query($mysqli,"SELECT * FROM settings WHERE company_id = 1");
$row = mysqli_fetch_array($sql_settings);
@@ -25,7 +40,6 @@ $config_smtp_password = $row['config_smtp_password'];
$config_mail_from_email = $row['config_mail_from_email'];
$config_mail_from_name = $row['config_mail_from_name'];
-
// HTTP-Only cookies
ini_set("session.cookie_httponly", True);
@@ -40,101 +54,81 @@ if (isset($_POST['login'])) {
// Sessions should start after the user has POSTed data
session_start();
- // Check recent failed login attempts for this IP (more than 10 failed logins in 5 mins)
- $row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT(log_id) AS failed_login_count FROM logs WHERE log_ip = '$ip' AND log_type = 'Login' AND log_action = 'Failed' AND log_created_at > (NOW() - INTERVAL 5 MINUTE)"));
- $failed_login_count = $row['failed_login_count'];
+ // Passed login brute force check
+ $email = strip_tags(mysqli_real_escape_string($mysqli, $_POST['email']));
+ $password = $_POST['password'];
- // Login brute force check
- if ($failed_login_count >= 10) {
+ $current_code = 0; // Default value
+ if (isset($_POST['current_code'])) {
+ $current_code = strip_tags(mysqli_real_escape_string($mysqli, $_POST['current_code']));
+ }
- // Logging
- mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login', log_action = 'Failed', log_description = 'Failed login attempt due to IP lockout', log_ip = '$ip', log_user_agent = '$user_agent'");
+ $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM users LEFT JOIN user_settings on users.user_id = user_settings.user_id WHERE user_email = '$email' AND user_archived_at IS NULL AND user_status = 1"));
- // Send an alert only count hits 10 to reduce flooding alerts (using 1 as "default" company)
- if($failed_login_count == 10){
- mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Lockout', notification = '$ip was locked out for repeated failed login attempts.', notification_timestamp = NOW() company_id = '1'");
- }
+ // Check password
+ if ($row && password_verify($password, $row['user_password'])) {
- // Inform user
- $response = '
IP Lockout - Please try again later.
';
+ // User password correct (partial login)
- } else {
- // Passed login brute force check
- $email = strip_tags(mysqli_real_escape_string($mysqli, $_POST['email']));
- $password = $_POST['password'];
+ // Set temporary user variables
+ $user_name = strip_tags(mysqli_real_escape_string($mysqli, $row['user_name']));
+ $user_id = $row['user_id'];
+ $user_email = $row['user_email'];
+ $token = $row['user_token'];
- $current_code = 0; // Default value
- if (isset($_POST['current_code'])) {
- $current_code = strip_tags(mysqli_real_escape_string($mysqli, $_POST['current_code']));
- }
+ // Checking for user 2FA
+ if (empty($token) || TokenAuth6238::verify($token, $current_code)) {
- $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM users LEFT JOIN user_settings on users.user_id = user_settings.user_id WHERE user_email = '$email' AND user_archived_at IS NULL AND user_status = 1"));
+ // FULL LOGIN SUCCESS - 2FA not configured or was successful
- // Check password
- if ($row && password_verify($password, $row['user_password'])) {
+ // Determine whether 2FA was used (for logs)
+ $extended_log = ''; // Default value
+ if ($current_code !== 0 ) {
+ $extended_log = 'with 2FA';
+ }
- // User password correct (partial login)
+ // Logging successful login
+ mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login', log_action = 'Success', log_description = '$user_name successfully logged in $extended_log', log_ip = '$ip', log_user_agent = '$user_agent', log_user_id = $user_id");
- // Set temporary user variables
- $user_name = strip_tags(mysqli_real_escape_string($mysqli, $row['user_name']));
- $user_id = $row['user_id'];
- $user_email = $row['user_email'];
- $token = $row['user_token'];
+ // Session info
+ $_SESSION['user_id'] = $user_id;
+ $_SESSION['user_name'] = $user_name;
+ $_SESSION['user_role'] = $row['user_role'];
+ $_SESSION['csrf_token'] = bin2hex(random_bytes(78));
+ $_SESSION['logged'] = TRUE;
- // Checking for user 2FA
- require_once("rfc6238.php");
- if (empty($token) || TokenAuth6238::verify($token, $current_code)) {
+ // Setup encryption session key
+ if (isset($row['user_specific_encryption_ciphertext']) && $row['user_role'] > 1) {
+ $user_encryption_ciphertext = $row['user_specific_encryption_ciphertext'];
+ $site_encryption_master_key = decryptUserSpecificKey($user_encryption_ciphertext, $password);
+ generateUserSessionKey($site_encryption_master_key);
- // FULL LOGIN SUCCESS - 2FA not configured or was successful
+ // Setup extension
+ if (isset($row['user_extension_key']) && !empty($row['user_extension_key'])) {
+ // Extension cookie
+ // Note: Browsers don't accept cookies with SameSite None if they are not HTTPS.
+ setcookie("user_extension_key", "$row[user_extension_key]", ['path' => '/', 'secure' => true, 'httponly' => true, 'samesite' => 'None']);
- // Determine whether 2FA was used (for logs)
- $extended_log = ''; // Default value
- if ($current_code !== 0 ) {
- $extended_log = 'with 2FA';
+ // Set PHP session in DB so we can access the session encryption data (above)
+ $user_php_session = session_id();
+ mysqli_query($mysqli, "UPDATE users SET user_php_session = '$user_php_session' WHERE user_id = '$user_id'");
}
+ }
- // Logging successful login
- mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login', log_action = 'Success', log_description = '$user_name successfully logged in $extended_log', log_ip = '$ip', log_user_agent = '$user_agent', log_user_id = $user_id");
-
- // Session info
- $_SESSION['user_id'] = $user_id;
- $_SESSION['user_name'] = $user_name;
- $_SESSION['user_role'] = $row['user_role'];
- $_SESSION['csrf_token'] = bin2hex(random_bytes(78));
- $_SESSION['logged'] = TRUE;
-
- // Setup encryption session key
- if (isset($row['user_specific_encryption_ciphertext']) && $row['user_role'] > 1) {
- $user_encryption_ciphertext = $row['user_specific_encryption_ciphertext'];
- $site_encryption_master_key = decryptUserSpecificKey($user_encryption_ciphertext, $password);
- generateUserSessionKey($site_encryption_master_key);
-
- // Setup extension
- if (isset($row['user_extension_key']) && !empty($row['user_extension_key'])) {
- // Extension cookie
- // Note: Browsers don't accept cookies with SameSite None if they are not HTTPS.
- setcookie("user_extension_key", "$row[user_extension_key]", ['path' => '/', 'secure' => true, 'httponly' => true, 'samesite' => 'None']);
-
- // Set PHP session in DB so we can access the session encryption data (above)
- $user_php_session = session_id();
- mysqli_query($mysqli, "UPDATE users SET user_php_session = '$user_php_session' WHERE user_id = '$user_id'");
- }
- }
-
- // Show start page/dashboard depending on role
- if ($row['user_role'] == 2) {
- header("Location: dashboard_technical.php");
- } else {
- header("Location: dashboard_financial.php");
- }
-
-
+ // Show start page/dashboard depending on role
+ if ($row['user_role'] == 2) {
+ header("Location: dashboard_technical.php");
} else {
+ header("Location: dashboard_financial.php");
+ }
- // MFA is configured and needs to be confirmed, or was unsuccessful
- // HTML code for the token input field
- $token_field = "
+ } else {
+
+ // MFA is configured and needs to be confirmed, or was unsuccessful
+
+ // HTML code for the token input field
+ $token_field = "
@@ -144,44 +138,43 @@ if (isset($_POST['login'])) {
";
- // Log/notify if MFA was unsuccessful
- if ($current_code !== 0) {
+ // Log/notify if MFA was unsuccessful
+ if ($current_code !== 0) {
- // Logging
- mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login', log_action = '2FA Failed', log_description = '$user_name failed 2FA', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW(), log_user_id = $user_id");
+ // Logging
+ mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login', log_action = '2FA Failed', log_description = '$user_name failed 2FA', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW(), log_user_id = $user_id");
- // Email the tech to advise their credentials may be compromised
- if (!empty($config_smtp_host)) {
- $subject = "Important: ITFlow failed 2FA login attempt for $user_name";
- $body = "Hi $user_name,
A recent login to ITFlow was unsuccessful due to an incorrect 2FA code. If you did not attempt this login, your credentials may be compromised.
Thanks, ITFlow";
+ // Email the tech to advise their credentials may be compromised
+ if (!empty($config_smtp_host)) {
+ $subject = "Important: ITFlow failed 2FA login attempt for $user_name";
+ $body = "Hi $user_name,
A recent login to ITFlow was unsuccessful due to an incorrect 2FA code. If you did not attempt this login, your credentials may be compromised.