Bruteforce protection
This commit is contained in:
parent
525e6f98c4
commit
9280cf3dfe
|
@ -8,6 +8,31 @@
|
||||||
// Functions
|
// Functions
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
function checkPost($args)
|
||||||
|
{
|
||||||
|
global $Security;
|
||||||
|
global $Login;
|
||||||
|
global $Language;
|
||||||
|
|
||||||
|
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']) )
|
||||||
|
{
|
||||||
|
Redirect::page('admin', 'dashboard');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bruteforce protection, add IP to blacklist.
|
||||||
|
$Security->addLoginFail();
|
||||||
|
Alert::set($Language->g('Username or password incorrect'));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Main before POST
|
// Main before POST
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
@ -18,15 +43,7 @@
|
||||||
|
|
||||||
if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
||||||
{
|
{
|
||||||
// Verify User sanitize the input
|
checkPost($_POST);
|
||||||
if( $Login->verifyUser($_POST['username'], $_POST['password']) )
|
|
||||||
{
|
|
||||||
Redirect::page('admin', 'dashboard');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Alert::set($Language->g('Username or password incorrect'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
@ -16,6 +16,10 @@ div.unit-80 {
|
||||||
margin-left: 1% !important;
|
margin-left: 1% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tools-alert {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------- FONTS AWESOME ----------- */
|
/* ----------- FONTS AWESOME ----------- */
|
||||||
.fa-right {
|
.fa-right {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<base href="<?php echo HTML_PATH_ADMIN_THEME ?>">
|
<base href="<?php echo HTML_PATH_ADMIN_THEME ?>">
|
||||||
<meta charset="utf-8">
|
<meta charset="<?php echo CHARSET ?>">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
<title><?php echo $layout['title'] ?></title>
|
<title><?php echo $layout['title'] ?></title>
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<base href="<?php echo HTML_PATH_ADMIN_THEME ?>">
|
<base href="<?php echo HTML_PATH_ADMIN_THEME ?>">
|
||||||
<meta charset="utf-8">
|
<meta charset="<?php echo CHARSET ?>">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
<title>Bludit Log in</title>
|
<title>Bludit</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="./css/kube.min.css?version=<?php echo BLUDIT_VERSION ?>">
|
<link rel="stylesheet" href="./css/kube.min.css?version=<?php echo BLUDIT_VERSION ?>">
|
||||||
<link rel="stylesheet" href="./css/default.css?version=<?php echo BLUDIT_VERSION ?>">
|
<link rel="stylesheet" href="./css/default.css?version=<?php echo BLUDIT_VERSION ?>">
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
<nav class="navbar nav-fullwidth">
|
<nav class="navbar nav-fullwidth">
|
||||||
<h1>Bludit</h1>
|
<h1>Bludit</h1>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="<?php echo HTML_PATH_ROOT ?>"><?php $Language->p('Home') ?></a></li>
|
<li><a href="<?php echo HTML_PATH_ROOT ?>"><?php $Language->p('Website') ?></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
@ -31,13 +31,13 @@
|
||||||
<div class="units-row">
|
<div class="units-row">
|
||||||
|
|
||||||
<!-- CONTENT -->
|
<!-- CONTENT -->
|
||||||
<div class="unit-centered unit-40" style="max-width: 500px">
|
<div class="unit-centered unit-40" style="max-width: 400px">
|
||||||
<div id="content">
|
<div id="content">
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
if(Alert::defined()) {
|
if(Alert::defined()) {
|
||||||
echo '<div class="tools-alert tools-alert-red">'.Alert::get().'</div>';
|
echo '<div class="tools-alert tools-alert-green">'.Alert::get().'</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load view
|
// Load view
|
||||||
|
@ -51,8 +51,6 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="footer">Bludit</div>
|
|
||||||
|
|
||||||
<!-- Plugins Login Body Begin -->
|
<!-- Plugins Login Body Begin -->
|
||||||
<?php Theme::plugins('loginBodyEnd') ?>
|
<?php Theme::plugins('loginBodyEnd') ?>
|
||||||
|
|
||||||
|
|
14
install.php
14
install.php
|
@ -273,6 +273,16 @@ function install($adminPassword, $email)
|
||||||
|
|
||||||
file_put_contents(PATH_DATABASES.'users.php', $dataHead.json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
|
file_put_contents(PATH_DATABASES.'users.php', $dataHead.json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
|
||||||
|
|
||||||
|
// File security.php
|
||||||
|
$data = array(
|
||||||
|
'minutesBlocked'=>5,
|
||||||
|
'numberFailuresAllowed'=>10,
|
||||||
|
'blackList'=>array()
|
||||||
|
);
|
||||||
|
|
||||||
|
file_put_contents(PATH_DATABASES.'security.php', $dataHead.json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
|
||||||
|
|
||||||
|
|
||||||
// File plugins/pages/db.php
|
// File plugins/pages/db.php
|
||||||
$data = array(
|
$data = array(
|
||||||
'homeLink'=>true,
|
'homeLink'=>true,
|
||||||
|
@ -364,7 +374,7 @@ if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<base href="admin/themes/default/">
|
<base href="admin/themes/default/">
|
||||||
<meta charset="utf-8">
|
<meta charset="<?php echo CHARSET ?>">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
<title><?php echo $Language->get('Bludit Installer') ?></title>
|
<title><?php echo $Language->get('Bludit Installer') ?></title>
|
||||||
|
@ -390,7 +400,7 @@ if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
||||||
// Missing requirements
|
// Missing requirements
|
||||||
if(!empty($system))
|
if(!empty($system))
|
||||||
{
|
{
|
||||||
echo '<div class="unit-centered unit-50">';
|
echo '<div class="boxInstallerForm unit-centered unit-50">';
|
||||||
echo '<table class="table-stripped">';
|
echo '<table class="table-stripped">';
|
||||||
|
|
||||||
foreach($system as $value) {
|
foreach($system as $value) {
|
||||||
|
|
|
@ -25,15 +25,15 @@ if ( in_array( strtolower( ini_get( 'magic_quotes_gpc' ) ), array( '1', 'on' ) )
|
||||||
}
|
}
|
||||||
|
|
||||||
// AJAX
|
// AJAX
|
||||||
if( $Login->isLogged() && ($layout['slug']==='ajax') )
|
if( $layout['slug']==='ajax' )
|
||||||
{
|
{
|
||||||
// Boot rules
|
if($Login->isLogged())
|
||||||
// Ajax doesn't load rules
|
{
|
||||||
|
|
||||||
// Load AJAX file
|
// Load AJAX file
|
||||||
if( Sanitize::pathFile(PATH_AJAX, $layout['parameters'].'.php') ) {
|
if( Sanitize::pathFile(PATH_AJAX, $layout['parameters'].'.php') ) {
|
||||||
include(PATH_AJAX.$layout['parameters'].'.php');
|
include(PATH_AJAX.$layout['parameters'].'.php');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ADMIN AREA
|
// ADMIN AREA
|
||||||
else
|
else
|
||||||
|
|
|
@ -97,6 +97,7 @@ include(PATH_KERNEL.'page.class.php');
|
||||||
include(PATH_KERNEL.'url.class.php');
|
include(PATH_KERNEL.'url.class.php');
|
||||||
include(PATH_KERNEL.'login.class.php');
|
include(PATH_KERNEL.'login.class.php');
|
||||||
include(PATH_KERNEL.'parsedown.class.php');
|
include(PATH_KERNEL.'parsedown.class.php');
|
||||||
|
include(PATH_KERNEL.'security.class.php');
|
||||||
|
|
||||||
// Include Helpers Classes
|
// Include Helpers Classes
|
||||||
include(PATH_HELPERS.'text.class.php');
|
include(PATH_HELPERS.'text.class.php');
|
||||||
|
@ -125,6 +126,7 @@ $dbUsers = new dbUsers();
|
||||||
$Site = new dbSite();
|
$Site = new dbSite();
|
||||||
$Url = new Url();
|
$Url = new Url();
|
||||||
$Parsedown = new Parsedown();
|
$Parsedown = new Parsedown();
|
||||||
|
$Security = new Security();
|
||||||
|
|
||||||
// HTML PATHs
|
// HTML PATHs
|
||||||
$base = (dirname(getenv('SCRIPT_NAME'))==DS)?'/':dirname(getenv('SCRIPT_NAME')).'/';
|
$base = (dirname(getenv('SCRIPT_NAME'))==DS)?'/':dirname(getenv('SCRIPT_NAME')).'/';
|
||||||
|
|
|
@ -65,7 +65,7 @@ class Login {
|
||||||
|
|
||||||
$user = $this->dbUsers->getDb($username);
|
$user = $this->dbUsers->getDb($username);
|
||||||
if($user==false) {
|
if($user==false) {
|
||||||
Log::set(__METHOD__.LOG_SEP.'Username not exist: '.$username);
|
Log::set(__METHOD__.LOG_SEP.'Username does not exist: '.$username);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ class Login {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log::set(__METHOD__.LOG_SEP.'Password are differents.');
|
Log::set(__METHOD__.LOG_SEP.'Password incorrect.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -5,7 +5,7 @@ class Security extends dbJSON
|
||||||
private $dbFields = array(
|
private $dbFields = array(
|
||||||
'minutesBlocked'=>5,
|
'minutesBlocked'=>5,
|
||||||
'numberFailuresAllowed'=>10,
|
'numberFailuresAllowed'=>10,
|
||||||
'blackList'=>array('numberFailures', 'lastFailure')
|
'blackList'=>array()
|
||||||
);
|
);
|
||||||
|
|
||||||
function __construct()
|
function __construct()
|
||||||
|
@ -27,12 +27,13 @@ class Security extends dbJSON
|
||||||
$lastFailure = $userBlack['lastFailure'];
|
$lastFailure = $userBlack['lastFailure'];
|
||||||
|
|
||||||
// Check if the IP is expired, then is not blocked.
|
// Check if the IP is expired, then is not blocked.
|
||||||
if($currentTime > $lastFailure + $this->db['minutesBlocked']) {
|
if($currentTime > $lastFailure + ($this->db['minutesBlocked']*60)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The IP has more failures than number of failures, then the IP is blocked.
|
// The IP has more failures than number of failures, then the IP is blocked.
|
||||||
if($numberFailures >= $this->db['numberFailuresAllowed']) {
|
if($numberFailures >= $this->db['numberFailuresAllowed']) {
|
||||||
|
Log::set(__METHOD__.LOG_SEP.'IP Blocked:'.$ip);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,13 +47,23 @@ class Security extends dbJSON
|
||||||
$currentTime = time();
|
$currentTime = time();
|
||||||
$numberFailures = 1;
|
$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))
|
||||||
|
{
|
||||||
$numberFailures = $userBlack['numberFailures'];
|
$numberFailures = $userBlack['numberFailures'];
|
||||||
$numberFailures = $numberFailures + 1;
|
$numberFailures = $numberFailures + 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->db['blackList'][$ip] = array('lastFailure'=>$currentTime, 'numberFailures'=>$numberFailures);
|
$this->db['blackList'][$ip] = array('lastFailure'=>$currentTime, 'numberFailures'=>$numberFailures);
|
||||||
|
|
||||||
|
Log::set(__METHOD__.LOG_SEP.'Blacklist, IP:'.$ip.', Number of failures:'.$numberFailures);
|
||||||
|
|
||||||
// Save the database
|
// Save the database
|
||||||
if( $this->save() === false ) {
|
if( $this->save() === false ) {
|
||||||
Log::set(__METHOD__.LOG_SEP.'Error occurred when trying to save the database file.');
|
Log::set(__METHOD__.LOG_SEP.'Error occurred when trying to save the database file.');
|
||||||
|
|
|
@ -155,5 +155,7 @@
|
||||||
"the-password-field-is-empty": "The password field is empty",
|
"the-password-field-is-empty": "The password field is empty",
|
||||||
"your-email-address-is-invalid":"Your email address is invalid.",
|
"your-email-address-is-invalid":"Your email address is invalid.",
|
||||||
"proceed-anyway": "Proceed anyway!",
|
"proceed-anyway": "Proceed anyway!",
|
||||||
"drafts":"Drafts"
|
"drafts":"Drafts",
|
||||||
|
"ip-address-has-been-blocked": "IP address has been blocked.",
|
||||||
|
"try-again-in-a-few-minutes": "Try again in a few minutes."
|
||||||
}
|
}
|
|
@ -153,5 +153,7 @@
|
||||||
"the-password-field-is-empty": "Debe completar el campo contraseña",
|
"the-password-field-is-empty": "Debe completar el campo contraseña",
|
||||||
"your-email-address-is-invalid":"Su dirección de correo es invalida.",
|
"your-email-address-is-invalid":"Su dirección de correo es invalida.",
|
||||||
"proceed-anyway": "Continuar de todas formas!",
|
"proceed-anyway": "Continuar de todas formas!",
|
||||||
"drafts":"Borradores"
|
"drafts":"Borradores",
|
||||||
|
"ip-address-has-been-blocked":"La direccion IP fue bloqueada.",
|
||||||
|
"try-again-in-a-few-minutes": "Vuelva a intentar en unos minutos."
|
||||||
}
|
}
|
Loading…
Reference in New Issue