Bruteforce protection
This commit is contained in:
parent
525e6f98c4
commit
9280cf3dfe
@ -8,6 +8,31 @@
|
||||
// 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
|
||||
// ============================================================================
|
||||
@ -18,15 +43,7 @@
|
||||
|
||||
if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
||||
{
|
||||
// Verify User sanitize the input
|
||||
if( $Login->verifyUser($_POST['username'], $_POST['password']) )
|
||||
{
|
||||
Redirect::page('admin', 'dashboard');
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert::set($Language->g('Username or password incorrect'));
|
||||
}
|
||||
checkPost($_POST);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
@ -16,6 +16,10 @@ div.unit-80 {
|
||||
margin-left: 1% !important;
|
||||
}
|
||||
|
||||
.tools-alert {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* ----------- FONTS AWESOME ----------- */
|
||||
.fa-right {
|
||||
margin-right: 5px;
|
||||
|
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<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">
|
||||
|
||||
<title><?php echo $layout['title'] ?></title>
|
||||
|
@ -2,10 +2,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<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">
|
||||
|
||||
<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/default.css?version=<?php echo BLUDIT_VERSION ?>">
|
||||
@ -23,7 +23,7 @@
|
||||
<nav class="navbar nav-fullwidth">
|
||||
<h1>Bludit</h1>
|
||||
<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>
|
||||
</nav>
|
||||
</div>
|
||||
@ -31,13 +31,13 @@
|
||||
<div class="units-row">
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="unit-centered unit-40" style="max-width: 500px">
|
||||
<div class="unit-centered unit-40" style="max-width: 400px">
|
||||
<div id="content">
|
||||
|
||||
<?php
|
||||
|
||||
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
|
||||
@ -51,8 +51,6 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div id="footer">Bludit</div>
|
||||
|
||||
<!-- Plugins Login Body Begin -->
|
||||
<?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 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
|
||||
$data = array(
|
||||
'homeLink'=>true,
|
||||
@ -364,7 +374,7 @@ if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
||||
<html lang="en">
|
||||
<head>
|
||||
<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">
|
||||
|
||||
<title><?php echo $Language->get('Bludit Installer') ?></title>
|
||||
@ -390,7 +400,7 @@ if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
||||
// Missing requirements
|
||||
if(!empty($system))
|
||||
{
|
||||
echo '<div class="unit-centered unit-50">';
|
||||
echo '<div class="boxInstallerForm unit-centered unit-50">';
|
||||
echo '<table class="table-stripped">';
|
||||
|
||||
foreach($system as $value) {
|
||||
|
@ -25,14 +25,14 @@ if ( in_array( strtolower( ini_get( 'magic_quotes_gpc' ) ), array( '1', 'on' ) )
|
||||
}
|
||||
|
||||
// AJAX
|
||||
if( $Login->isLogged() && ($layout['slug']==='ajax') )
|
||||
if( $layout['slug']==='ajax' )
|
||||
{
|
||||
// Boot rules
|
||||
// Ajax doesn't load rules
|
||||
|
||||
// Load AJAX file
|
||||
if( Sanitize::pathFile(PATH_AJAX, $layout['parameters'].'.php') ) {
|
||||
include(PATH_AJAX.$layout['parameters'].'.php');
|
||||
if($Login->isLogged())
|
||||
{
|
||||
// Load AJAX file
|
||||
if( Sanitize::pathFile(PATH_AJAX, $layout['parameters'].'.php') ) {
|
||||
include(PATH_AJAX.$layout['parameters'].'.php');
|
||||
}
|
||||
}
|
||||
}
|
||||
// ADMIN AREA
|
||||
@ -73,4 +73,4 @@ else
|
||||
|
||||
// Plugins after admin area loaded
|
||||
Theme::plugins('afterAdminLoad');
|
||||
}
|
||||
}
|
@ -97,6 +97,7 @@ include(PATH_KERNEL.'page.class.php');
|
||||
include(PATH_KERNEL.'url.class.php');
|
||||
include(PATH_KERNEL.'login.class.php');
|
||||
include(PATH_KERNEL.'parsedown.class.php');
|
||||
include(PATH_KERNEL.'security.class.php');
|
||||
|
||||
// Include Helpers Classes
|
||||
include(PATH_HELPERS.'text.class.php');
|
||||
@ -125,6 +126,7 @@ $dbUsers = new dbUsers();
|
||||
$Site = new dbSite();
|
||||
$Url = new Url();
|
||||
$Parsedown = new Parsedown();
|
||||
$Security = new Security();
|
||||
|
||||
// HTML PATHs
|
||||
$base = (dirname(getenv('SCRIPT_NAME'))==DS)?'/':dirname(getenv('SCRIPT_NAME')).'/';
|
||||
|
@ -65,7 +65,7 @@ class Login {
|
||||
|
||||
$user = $this->dbUsers->getDb($username);
|
||||
if($user==false) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Username not exist: '.$username);
|
||||
Log::set(__METHOD__.LOG_SEP.'Username does not exist: '.$username);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ class Login {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Log::set(__METHOD__.LOG_SEP.'Password are differents.');
|
||||
Log::set(__METHOD__.LOG_SEP.'Password incorrect.');
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -113,4 +113,4 @@ class Login {
|
||||
return Session::destroy();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ class Security extends dbJSON
|
||||
private $dbFields = array(
|
||||
'minutesBlocked'=>5,
|
||||
'numberFailuresAllowed'=>10,
|
||||
'blackList'=>array('numberFailures', 'lastFailure')
|
||||
'blackList'=>array()
|
||||
);
|
||||
|
||||
function __construct()
|
||||
@ -27,12 +27,13 @@ class Security extends dbJSON
|
||||
$lastFailure = $userBlack['lastFailure'];
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -46,13 +47,23 @@ class Security extends dbJSON
|
||||
$currentTime = time();
|
||||
$numberFailures = 1;
|
||||
|
||||
if(isset($this->db['blackList'][$ip])) {
|
||||
$numberFailures = $userBlack['numberFailures'];
|
||||
$numberFailures = $numberFailures + 1;
|
||||
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 = $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.');
|
||||
|
@ -155,5 +155,7 @@
|
||||
"the-password-field-is-empty": "The password field is empty",
|
||||
"your-email-address-is-invalid":"Your email address is invalid.",
|
||||
"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",
|
||||
"your-email-address-is-invalid":"Su dirección de correo es invalida.",
|
||||
"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
Block a user