Login and Security improves
This commit is contained in:
parent
0be75f22c4
commit
7f8e012486
|
@ -91,7 +91,7 @@ function checkGet($args)
|
|||
}
|
||||
|
||||
// Bruteforce protection, add IP to blacklist.
|
||||
$Security->addLoginFail();
|
||||
$Security->addToBlacklist();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,27 +8,26 @@
|
|||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
function checkPost($args)
|
||||
function checkLogin($args)
|
||||
{
|
||||
global $Security;
|
||||
global $Login;
|
||||
global $Language;
|
||||
|
||||
if($Security->isBlocked()) {
|
||||
if ($Security->isBlocked()) {
|
||||
Alert::set($Language->g('IP address has been blocked').'<br>'.$Language->g('Try again in a few minutes'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify User sanitize the input
|
||||
if( $Login->verifyUser($_POST['username'], $_POST['password']) ) {
|
||||
if ($Login->verifyUser($_POST['username'], $_POST['password'])) {
|
||||
// Renew the token. This token will be the same inside the session for multiple forms.
|
||||
$Security->generateTokenCSRF();
|
||||
Redirect::page('dashboard');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Bruteforce protection, add IP to blacklist.
|
||||
$Security->addLoginFail();
|
||||
// Bruteforce protection, add IP to the blacklist
|
||||
$Security->addToBlacklist();
|
||||
|
||||
// Create alert
|
||||
Alert::set($Language->g('Username or password incorrect'));
|
||||
|
@ -44,9 +43,9 @@ function checkPost($args)
|
|||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
||||
if ($_SERVER['REQUEST_METHOD']=='POST')
|
||||
{
|
||||
checkPost($_POST);
|
||||
checkLogin($_POST);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
@ -144,6 +144,9 @@ $(document).ready(function() {
|
|||
<?php
|
||||
if( Sanitize::pathFile(PATH_ADMIN_VIEWS, $layout['view'].'.php') ) {
|
||||
include(PATH_ADMIN_VIEWS.$layout['view'].'.php');
|
||||
} else {
|
||||
echo '<h1 style="width:100%; text-align:center">Hey!</h1>';
|
||||
echo '<h2 style="width:100%; text-align:center">Have you seen my ball?</h2>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<form method="post" action="" class="uk-form" autocomplete="off">
|
||||
|
||||
<input type="hidden" id="jstoken" name="tokenCSRF" value="<?php $Security->printTokenCSRF() ?>">
|
||||
<input type="hidden" id="jstoken" name="tokenCSRF" value="<?php echo $Security->getTokenCSRF() ?>">
|
||||
|
||||
<div class="uk-form-row">
|
||||
<input name="email" class="uk-width-1-1 uk-form-large" placeholder="<?php $L->p('Email') ?>" type="text">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<form method="post" action="" class="uk-form" autocomplete="off">
|
||||
|
||||
<input type="hidden" id="jstoken" name="tokenCSRF" value="<?php $Security->printTokenCSRF() ?>">
|
||||
<input type="hidden" id="jstoken" name="tokenCSRF" value="<?php echo $Security->getTokenCSRF() ?>">
|
||||
|
||||
<div class="uk-form-row">
|
||||
<input name="username" class="uk-width-1-1 uk-form-large" placeholder="<?php $L->p('Username') ?>" type="text">
|
||||
|
|
|
@ -50,14 +50,12 @@ else
|
|||
// User not logged.
|
||||
// Slug is login.
|
||||
// Slug is login-email.
|
||||
if($Url->notFound() || !$Login->isLogged() || ($Url->slug()==='login') || ($Url->slug()==='login-email') )
|
||||
{
|
||||
if($Url->notFound() || !$Login->isLogged() || ($Url->slug()==='login') || ($Url->slug()==='login-email') ) {
|
||||
$layout['controller'] = 'login';
|
||||
$layout['view'] = 'login';
|
||||
$layout['template'] = 'login.php';
|
||||
|
||||
if($Url->slug()==='login-email')
|
||||
{
|
||||
if ($Url->slug()==='login-email') {
|
||||
$layout['controller'] = 'login-email';
|
||||
$layout['view'] = 'login-email';
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ define('DB_CATEGORIES', PATH_DATABASES.'categories.php');
|
|||
define('DB_TAGS', PATH_DATABASES.'tags.php');
|
||||
define('DB_SYSLOG', PATH_DATABASES.'syslog.php');
|
||||
define('DB_USERS', PATH_DATABASES.'users.php');
|
||||
define('DB_SECURITY', PATH_DATABASES.'security.php');
|
||||
|
||||
// Log separator
|
||||
define('LOG_SEP', ' | ');
|
||||
|
|
|
@ -185,19 +185,18 @@ class dbUsers extends dbJSON
|
|||
return $token;
|
||||
}
|
||||
|
||||
// ---- OLD
|
||||
// Returns array with the username databases filtered by username, FALSE otherwise
|
||||
public function getDb($username)
|
||||
public function getDB($username)
|
||||
{
|
||||
if($this->exists($username)) {
|
||||
$user = $this->db[$username];
|
||||
|
||||
return $user;
|
||||
if ($this->exists($username)) {
|
||||
return $this->db[$username];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---- OLD
|
||||
|
||||
|
||||
public function getAll()
|
||||
{
|
||||
return $this->db;
|
||||
|
|
|
@ -55,13 +55,9 @@
|
|||
public static function destroy()
|
||||
{
|
||||
session_destroy();
|
||||
|
||||
unset($_SESSION);
|
||||
|
||||
self::$started = false;
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'Session destroyed.');
|
||||
|
||||
return !isset($_SESSION);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,26 @@ class Login {
|
|||
return Session::get('role');
|
||||
}
|
||||
|
||||
// Returns TRUE if the user is logged, FALSE otherwise
|
||||
public function isLogged()
|
||||
{
|
||||
if (Session::get('fingerPrint')===$this->fingerPrint()) {
|
||||
$username = Session::get('username');
|
||||
if (!empty($username)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Log::set(__METHOD__.LOG_SEP.'Session username empty, destroy the session.');
|
||||
Session::destroy();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'FingerPrint are differents. Current fingerPrint: '.Session::get('fingerPrint').' !== Current fingerPrint: '.$this->fingerPrint());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the session for the user logged
|
||||
public function setLogin($username, $role)
|
||||
{
|
||||
Session::set('username', $username);
|
||||
|
@ -26,30 +46,12 @@ class Login {
|
|||
Session::set('fingerPrint', $this->fingerPrint());
|
||||
Session::set('sessionTime', time());
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'Set fingerPrint: '.$this->fingerPrint());
|
||||
}
|
||||
|
||||
public function isLogged()
|
||||
{
|
||||
if(Session::get('fingerPrint')===$this->fingerPrint())
|
||||
{
|
||||
$username = Session::get('username');
|
||||
|
||||
if(!empty($username)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Log::set(__METHOD__.LOG_SEP.'Session username empty: '.$username);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::set(__METHOD__.LOG_SEP.'FingerPrint are differents. Session fingerPrint: '.Session::get('fingerPrint').' !== Current fingerPrint: '.$this->fingerPrint());
|
||||
}
|
||||
|
||||
return false;
|
||||
Log::set(__METHOD__.LOG_SEP.'User logged, fingerprint: '.$this->fingerPrint());
|
||||
}
|
||||
|
||||
// Check if the username and the password are valid
|
||||
// Returns TRUE if valid and set the session
|
||||
// Returns FALSE for invalid username or password
|
||||
public function verifyUser($username, $password)
|
||||
{
|
||||
$username = Sanitize::html($username);
|
||||
|
@ -58,25 +60,21 @@ class Login {
|
|||
$username = trim($username);
|
||||
$password = trim($password);
|
||||
|
||||
if(empty($username) || empty($password)) {
|
||||
if (empty($username) || empty($password)) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Username or password empty. Username: '.$username.' - Password: '.$password);
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->dbUsers->getDb($username);
|
||||
$user = $this->dbUsers->getDB($username);
|
||||
if($user==false) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Username does not exist: '.$username);
|
||||
return false;
|
||||
}
|
||||
|
||||
$passwordHash = sha1($password.$user['salt']);
|
||||
|
||||
if($passwordHash === $user['password'])
|
||||
{
|
||||
$passwordHash = $this->dbUsers->generatePasswordHash($password, $user['salt']);
|
||||
if ($passwordHash===$user['password']) {
|
||||
$this->setLogin($username, $user['role']);
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'User logged succeeded by username and password - Username: '.$username);
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -130,27 +128,14 @@ class Login {
|
|||
return false;
|
||||
}
|
||||
|
||||
public function fingerPrint($random=false)
|
||||
public function fingerPrint()
|
||||
{
|
||||
// User agent
|
||||
$agent = getenv('HTTP_USER_AGENT');
|
||||
if(empty($agent)) {
|
||||
$agent = 'Bludit/1.0 (Mr Nibbler Protocol)';
|
||||
if (empty($agent)) {
|
||||
$agent = 'Bludit/2.0 (Mr Nibbler Protocol)';
|
||||
}
|
||||
|
||||
// User IP
|
||||
if(getenv('HTTP_X_FORWARDED_FOR'))
|
||||
$ip = getenv('HTTP_X_FORWARDED_FOR');
|
||||
elseif(getenv('HTTP_CLIENT_IP'))
|
||||
$ip = getenv('HTTP_CLIENT_IP');
|
||||
else
|
||||
$ip = getenv('REMOTE_ADDR');
|
||||
|
||||
if($random) {
|
||||
return sha1(mt_rand().$agent.$ip);
|
||||
}
|
||||
|
||||
// DEBUG: Ver CLIENT IP, hay veces que retorna la ip ::1 y otras 127.0.0.1
|
||||
return sha1($agent);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
<?php defined('BLUDIT') or die('Bludit Badass CMS.');
|
||||
|
||||
class Security extends dbJSON
|
||||
{
|
||||
private $dbFields = array(
|
||||
'key1'=>'Where we go we dont need roads',
|
||||
'minutesBlocked'=>5,
|
||||
'numberFailuresAllowed'=>10,
|
||||
'blackList'=>array()
|
||||
|
@ -11,51 +10,33 @@ class Security extends dbJSON
|
|||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct(PATH_DATABASES.'security.php');
|
||||
parent::__construct(DB_SECURITY);
|
||||
}
|
||||
|
||||
// Authentication key
|
||||
// --------------------------------------------------------------------
|
||||
public function key1()
|
||||
{
|
||||
return $this->db['key1'];
|
||||
}
|
||||
|
||||
|
||||
// ====================================================
|
||||
// TOKEN FOR CSRF
|
||||
// ====================================================
|
||||
|
||||
// Generate and save the token in Session.
|
||||
// Generate and save the token in Session
|
||||
public function generateTokenCSRF()
|
||||
{
|
||||
$token = Text::randomText(8);
|
||||
$token = sha1($token);
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'New tokenCSRF was generated '.$token);
|
||||
|
||||
$token = sha1( uniqid().time() );
|
||||
Session::set('tokenCSRF', $token);
|
||||
}
|
||||
|
||||
// Validate the token.
|
||||
// Validate the token
|
||||
public function validateTokenCSRF($token)
|
||||
{
|
||||
$sessionToken = Session::get('tokenCSRF');
|
||||
|
||||
$sessionToken = $this->getTokenCSRF();
|
||||
return ( !empty($sessionToken) && ($sessionToken===$token) );
|
||||
}
|
||||
|
||||
// Returns the token.
|
||||
// Returns the token
|
||||
public function getTokenCSRF()
|
||||
{
|
||||
return Session::get('tokenCSRF');
|
||||
}
|
||||
|
||||
public function printTokenCSRF()
|
||||
{
|
||||
echo Session::get('tokenCSRF');
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// BRUTE FORCE PROTECTION
|
||||
// ====================================================
|
||||
|
@ -64,7 +45,7 @@ class Security extends dbJSON
|
|||
{
|
||||
$ip = $this->getUserIp();
|
||||
|
||||
if(!isset($this->db['blackList'][$ip])) {
|
||||
if (!isset($this->db['blackList'][$ip])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -73,51 +54,42 @@ class Security extends dbJSON
|
|||
$numberFailures = $userBlack['numberFailures'];
|
||||
$lastFailure = $userBlack['lastFailure'];
|
||||
|
||||
// Check if the IP is expired, then is not blocked.
|
||||
if($currentTime > $lastFailure + ($this->db['minutesBlocked']*60)) {
|
||||
// Check if the IP is expired, then is not blocked
|
||||
if ($currentTime > $lastFailure + ($this->db['minutesBlocked']*60)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The IP has more failures than number of failures, then the IP is blocked.
|
||||
if($numberFailures >= $this->db['numberFailuresAllowed']) {
|
||||
// The IP has more failures than number of failures, then the IP is blocked
|
||||
if ($numberFailures >= $this->db['numberFailuresAllowed']) {
|
||||
Log::set(__METHOD__.LOG_SEP.'IP Blocked:'.$ip);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise the IP is not blocked.
|
||||
// Otherwise the IP is not blocked
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addLoginFail()
|
||||
// Add or update the current client IP on the blacklist
|
||||
public function addToBlacklist()
|
||||
{
|
||||
$ip = $this->getUserIp();
|
||||
$currentTime = time();
|
||||
$numberFailures = 1;
|
||||
|
||||
if(isset($this->db['blackList'][$ip]))
|
||||
{
|
||||
if (isset($this->db['blackList'][$ip])) {
|
||||
$userBlack = $this->db['blackList'][$ip];
|
||||
$lastFailure = $userBlack['lastFailure'];
|
||||
|
||||
// Check if the IP is expired, then renew the number of failures.
|
||||
if($currentTime <= $lastFailure + ($this->db['minutesBlocked']*60))
|
||||
{
|
||||
// Check if the IP is expired, then renew the number of failures
|
||||
if($currentTime <= $lastFailure + ($this->db['minutesBlocked']*60)) {
|
||||
$numberFailures = $userBlack['numberFailures'];
|
||||
$numberFailures = $numberFailures + 1;
|
||||
}
|
||||
}
|
||||
|
||||
$this->db['blackList'][$ip] = array('lastFailure'=>$currentTime, 'numberFailures'=>$numberFailures);
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'Blacklist, IP:'.$ip.', Number of failures:'.$numberFailures);
|
||||
|
||||
// Save the database
|
||||
if( $this->save() === false ) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Error occurred when trying to save the database file.');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function getNumberFailures($ip=null)
|
||||
|
@ -134,14 +106,13 @@ class Security extends dbJSON
|
|||
|
||||
public function getUserIp()
|
||||
{
|
||||
// User IP
|
||||
if(getenv('HTTP_X_FORWARDED_FOR'))
|
||||
if (getenv('HTTP_X_FORWARDED_FOR')) {
|
||||
$ip = getenv('HTTP_X_FORWARDED_FOR');
|
||||
elseif(getenv('HTTP_CLIENT_IP'))
|
||||
} elseif (getenv('HTTP_CLIENT_IP')) {
|
||||
$ip = getenv('HTTP_CLIENT_IP');
|
||||
else
|
||||
} else {
|
||||
$ip = getenv('REMOTE_ADDR');
|
||||
|
||||
}
|
||||
return $ip;
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
|
@ -418,10 +418,7 @@ function install($adminPassword, $email, $timezone)
|
|||
file_put_contents(PATH_DATABASES.'syslog.php', $dataHead.json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
|
||||
|
||||
// File security.php
|
||||
$randomKey = sha1( uniqid() );
|
||||
|
||||
$data = array(
|
||||
'key1'=>$randomKey,
|
||||
'minutesBlocked'=>5,
|
||||
'numberFailuresAllowed'=>10,
|
||||
'blackList'=>array()
|
||||
|
|
Loading…
Reference in New Issue