Bruteforce protection

This commit is contained in:
dignajar 2015-08-17 23:02:19 -03:00
parent 525e6f98c4
commit 9280cf3dfe
11 changed files with 83 additions and 37 deletions

View File

@ -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);
}
// ============================================================================

View File

@ -16,6 +16,10 @@ div.unit-80 {
margin-left: 1% !important;
}
.tools-alert {
text-align: center;
}
/* ----------- FONTS AWESOME ----------- */
.fa-right {
margin-right: 5px;

View File

@ -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>

View File

@ -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') ?>

View File

@ -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) {

View File

@ -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

View File

@ -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')).'/';

View File

@ -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;

View File

@ -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.');

View 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."
}

View File

@ -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."
}