From 34f66afe5ec26e5d2f081e2d3ecde5a7de2fdecc Mon Sep 17 00:00:00 2001 From: REJack Date: Fri, 20 May 2016 13:40:10 +0200 Subject: [PATCH] #137 Non-user based DDoS check added a new table for login_attempts (in both SQL files) added 2 config vars `login_attempts`(db) & `remove_successful_attempts` changed function `reset_login_attempts()` (removed user_id and changed where to ip_address and timestamp from user_id only) changed function `update_login_attempts()` (removed user_id and changed where to ip_address and timestamp from email/user_id only) changed function `login()` (removed arguments from changed functions, added abilty to enable/disable removing login attempt after successful login) --- application/config/aauth.php | 10 +++-- application/libraries/Aauth.php | 74 +++++++++++++++++++-------------- sql/Aauth_v2.sql | 15 +++++++ sql/Aauth_v2_BCrypt.sql | 15 +++++++ 4 files changed, 79 insertions(+), 35 deletions(-) diff --git a/application/config/aauth.php b/application/config/aauth.php index 7b86738..460add1 100644 --- a/application/config/aauth.php +++ b/application/config/aauth.php @@ -31,6 +31,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); | ['perm_to_user'] The table which contains permissions for users | ['pms'] The table which contains private messages | ['user_variables'] The table which contains users variables +| ['login_attempts'] The table which contains login attempts | | ['remember'] Remember time elapsed after connecting and automatic LogOut | @@ -49,11 +50,12 @@ defined('BASEPATH') OR exit('No direct script access allowed'); | ['totp_active'] The Time-based One-time Password Algorithm | ['totp_only_on_ip_change'] TOTP only on IP Change | ['totp_reset_over_reset_password'] TOTP reset over reset Password -| ['totp_two_step_login'] enables TOTP two step login +| ['totp_two_step_login'] Enables/Disables TOTP two step login | ['totp_two_step_login_redirect'] Redirect path to TOTP Verification page used by control() & is_allowed() | | ['max_login_attempt'] Login attempts time interval (default 10 times in one hour) | ['max_login_attempt_time_period'] Period of time for max login attempts (default "5 minutes") +| ['remove_successful_attempts'] Enables/Disables removing login attempt after successful login | | ['login_with_name'] Login Identificator, if TRUE username needed to login else email address. | @@ -66,8 +68,8 @@ defined('BASEPATH') OR exit('No direct script access allowed'); | ['verification_link'] Link for verification without site_url or base_url | ['reset_password_link'] Link for reset_password without site_url or base_url | -| ['hash'] Name of selected hashing algorithm (e.g. "md5", "sha256", "haval160,4", etc..) -| Please, run hash_algos() for know your all supported algorithms +| ['hash'] Name of selected hashing algorithm (e.g. "md5", "sha256", "haval160,4", etc..) +| Please, run hash_algos() for know your all supported algorithms | ['use_password_hash'] True to use PHP's own password_hash() function with BCrypt, needs PHP5.5 or higher | ['password_hash_algo'] password_hash algorithm (PASSWORD_DEFAULT, PASSWORD_BCRYPT) for details see http://php.net/manual/de/password.constants.php | ['password_hash_options'] password_hash options array for details see http://php.net/manual/en/function.password-hash.php @@ -93,6 +95,7 @@ $config_aauth["default"] = array( 'perm_to_user' => 'aauth_perm_to_user', 'pms' => 'aauth_pms', 'user_variables' => 'aauth_user_variables', + 'login_attempts' => 'aauth_login_attempts', 'remember' => ' +3 days', @@ -116,6 +119,7 @@ $config_aauth["default"] = array( 'max_login_attempt' => 10, 'max_login_attempt_time_period' => "5 minutes", + 'remove_successful_attempts' => true, 'login_with_name' => false, diff --git a/application/libraries/Aauth.php b/application/libraries/Aauth.php index 11d5940..f892b69 100644 --- a/application/libraries/Aauth.php +++ b/application/libraries/Aauth.php @@ -174,7 +174,7 @@ class Aauth { $row = $query->row(); // only email found and login attempts exceeded - if ($query->num_rows() > 0 && $this->config_vars['ddos_protection'] && ! $this->update_login_attempts($row->email)) { + if ($query->num_rows() > 0 && $this->config_vars['ddos_protection'] && ! $this->update_login_attempts()) { $this->error($this->CI->lang->line('aauth_error_login_attempts_exceeded')); return FALSE; @@ -352,7 +352,10 @@ class Aauth { // update last login $this->update_last_login($row->id); $this->update_activity(); - $this->reset_login_attempts($row->id); + + if($this->config_vars['remove_successful_attempts'] == TRUE){ + $this->reset_login_attempts(); + } return TRUE; } @@ -536,15 +539,18 @@ class Aauth { /** * Reset last login attempts - * Sets a users 'last login attempts' to null - * @param int $user_id User id to reset + * Removes a Login Attempt * @return bool Reset fails/succeeds */ - public function reset_login_attempts($user_id) { - - $data['login_attempts'] = null; - $this->aauth_db->where('id', $user_id); - return $this->aauth_db->update($this->config_vars['users'], $data); + public function reset_login_attempts() { + $ip_address = $this->CI->input->ip_address(); + $this->aauth_db->where( + array( + 'ip_address'=>$ip_address, + 'timestamp >='=>strtotime("-".$this->config_vars['max_login_attempt_time_period']) + ) + ); + return $this->aauth_db->delete($this->config_vars['login_attempts']); } /** @@ -645,34 +651,38 @@ class Aauth { //tested /** * Update login attempt and if exceeds return FALSE - * Update user's last login attemp date and number date - * @param string $email User email * @return bool */ - public function update_login_attempts($email) { - - $user_id = $this->get_user_id($email); - - $query = $this->aauth_db->where('id', $user_id); - $query = $this->aauth_db->get( $this->config_vars['users'] ); - $row = $query->row(); - - $data = array(); - $data['last_login_attempt'] = date("Y-m-d H:i:s"); + public function update_login_attempts() { + $ip_address = $this->CI->input->ip_address(); + $query = $this->aauth_db->where( + array( + 'ip_address'=>$ip_address, + 'timestamp >='=>strtotime("-".$this->config_vars['max_login_attempt_time_period']) + ) + ); + $query = $this->aauth_db->get( $this->config_vars['login_attempts'] ); - if (strtotime($row->last_login_attempt) > strtotime("-".$this->config_vars['max_login_attempt_time_period'])) { + if($query->num_rows() == 0){ + $data = array(); + $data['ip_address'] = $ip_address; + $data['timestamp']= date("Y-m-d H:i:s"); + $data['login_attempts']= 1; + $this->aauth_db->insert($this->config_vars['login_attempts'], $data); + return TRUE; + }else{ + $row = $query->row(); + $data = array(); + $data['timestamp'] = date("Y-m-d H:i:s"); $data['login_attempts'] = $row->login_attempts + 1; - } else { - $data['login_attempts'] = 1; - } - - $this->aauth_db->where('id', $user_id); - $this->aauth_db->update($this->config_vars['users'], $data); + $this->aauth_db->where('id', $row->id); + $this->aauth_db->update($this->config_vars['login_attempts'], $data); - if ( $data['login_attempts'] > $this->config_vars['max_login_attempt'] ) { - return FALSE; - } else { - return TRUE; + if ( $data['login_attempts'] > $this->config_vars['max_login_attempt'] ) { + return FALSE; + } else { + return TRUE; + } } } diff --git a/sql/Aauth_v2.sql b/sql/Aauth_v2.sql index e7735b2..2479566 100644 --- a/sql/Aauth_v2.sql +++ b/sql/Aauth_v2.sql @@ -160,3 +160,18 @@ CREATE TABLE `aauth_group_to_group` ( -- Records of aauth_perm_to_group -- ---------------------------- +-- ---------------------------- +-- Table structure for `aauth_login_attempts` +-- ---------------------------- + +CREATE TABLE IF NOT EXISTS `aauth_login_attempts` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ip_address` varchar(39) DEFAULT '0', + `timestamp` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `login_attempts` tinyint(2) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- ---------------------------- +-- Records of aauth_login_attempts +-- ---------------------------- diff --git a/sql/Aauth_v2_BCrypt.sql b/sql/Aauth_v2_BCrypt.sql index 76c7a7c..c030649 100644 --- a/sql/Aauth_v2_BCrypt.sql +++ b/sql/Aauth_v2_BCrypt.sql @@ -160,3 +160,18 @@ CREATE TABLE `aauth_group_to_group` ( -- Records of aauth_perm_to_group -- ---------------------------- +-- ---------------------------- +-- Table structure for `aauth_login_attempts` +-- ---------------------------- + +CREATE TABLE IF NOT EXISTS `aauth_login_attempts` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ip_address` varchar(39) DEFAULT '0', + `timestamp` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `login_attempts` tinyint(2) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- ---------------------------- +-- Records of aauth_login_attempts +-- ----------------------------