Browse Source

10.2.dev16 journalisation + blocage brute force login

pull/9/head
Fred Tempez 2 years ago
parent
commit
dd1d3f793f
  1. 13
      core/core.php
  2. 46
      core/module/config/config.php
  3. 70
      core/module/config/view/index/index.php
  4. 3
      core/module/install/ressource/defaultdata.php
  5. 29
      core/module/user/user.php
  6. 6
      module/blog/view/index/index.php
  7. 0
      site/file/source/screenshot.png

13
core/core.php

@ -39,7 +39,7 @@ class common {
const ACCESS_TIMER = 1800;
// Numéro de version
const ZWII_VERSION = '10.2.00.dev14';
const ZWII_VERSION = '10.2.00.dev16';
const ZWII_UPDATE_CHANNEL = "v10";
public static $actions = [];
@ -1312,6 +1312,7 @@ class common {
$this->deleteData(['admin','colorButtonText']);
$this->setData(['config', 'connect', 'attempt',3]);
$this->setData(['config', 'connect', 'timeout',360]);
$this->setData(['config', 'connect', 'log',false]);
$this->setData(['core', 'dataVersion', 10200]);
}
}
@ -1581,6 +1582,15 @@ class core extends common {
header('Location:' . helper::baseUrl() . 'install');
exit();
}
// Journalisation
$dataLog = strftime('%d/%m/%y',time()) . ';' . strftime('%R',time()) . ';' ;
$dataLog .= $_SERVER['REMOTE_ADDR'] . ';' ;
$dataLog .= $this->getUser('id') . ';' ;
$dataLog .= $this->getUrl();
$dataLog .= PHP_EOL;
if ($this->getData(['config','connect','log'])) {
file_put_contents(self::DATA_DIR . 'journal.log', $dataLog, FILE_APPEND);
}
// Force la déconnexion des membres bannis ou d'une seconde session
if (
$this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
@ -1661,7 +1671,6 @@ class core extends common {
$this->setData(['user',$this->getuser('id'),'accessUrl',$this->getUrl()]);
$this->setData(['user',$this->getuser('id'),'accessTimer',time()]);
}
// Breadcrumb
$title = $this->getData(['page', $this->getUrl(0), 'title']);
if (!empty($this->getData(['page', $this->getUrl(0), 'parentPageId'])) &&

46
core/module/config/config.php

@ -24,7 +24,9 @@ class config extends common {
'index' => self::GROUP_ADMIN,
'manage' => self::GROUP_ADMIN,
'updateBaseUrl' => self::GROUP_ADMIN,
'script' => self::GROUP_ADMIN
'script' => self::GROUP_ADMIN,
'logReset' => self::GROUP_ADMIN,
'logDownload'=> self::GROUP_ADMIN
];
public static $timezones = [
@ -457,6 +459,7 @@ class config extends common {
'connect' => [
'attempt' => $this->getInput('configConnectAttempt',helper::FILTER_INT),
'timeout' => $this->getInput('configConnectTimeout',helper::FILTER_INT),
'log' => $this->getInput('configConnectLog',helper::FILTER_BOOLEAN)
]
]
]);
@ -597,6 +600,47 @@ class config extends common {
]);
}
/**
* Vider le fichier de log
*/
public function logReset() {
unlink(self::DATA_DIR . 'journal.log');
// Valeurs en sortie
$this->addOutput([
'title' => 'Configuration',
'view' => 'index',
'notification' => 'Journal réinitialisé avec succès',
'state' => true
]);
}
/**
* Télécharger le fichier de log
*/
public function logDownload() {
// Creation du ZIP
$fileName = self::DATA_DIR . 'journal.log';
// Téléchargement du ZIP
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize($fileName));
readfile( $fileName);
// Valeurs en sortie
$this->addOutput([
'display' => self::DISPLAY_RAW
]);
// Valeurs en sortie
$this->addOutput([
'title' => 'Configuration',
'view' => 'index'
]);
}
/**
* Fonction de parcours des données de module
* @param string $find donnée à rechercher

70
core/module/config/view/index/index.php

@ -148,7 +148,6 @@
</div>
<div class="col3">
<?php echo template::button('configUpdateForced', [
'class' => 'buttonRed',
'ico' => 'download-cloud',
'href' => helper::baseUrl() . 'install/update',
'value' => 'Mise à jour manuelle',
@ -286,27 +285,6 @@
</div>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Connexion</h4>
<div class="row">
<div class="col4">
<?php echo template::select('configConnectAttempt', $module::$connectAttempt , [
'label' => 'Echecs avant blocage',
'selected' => $this->getData(['config', 'connect', 'attempt'])
]); ?>
</div>
<div class="col4">
<?php echo template::select('configConnectTimeout', $module::$connectTimeout , [
'label' => 'Durée du blocage',
'selected' => $this->getData(['config', 'connect', 'timeout'])
]); ?>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
@ -374,7 +352,21 @@
<div class="block">
<h4>Options avancées</h4>
<div class="row">
<div class="col3 offset1">
<?php echo template::select('configConnectAttempt', $module::$connectAttempt , [
'label' => 'Tentatives de logins',
'selected' => $this->getData(['config', 'connect', 'attempt'])
]); ?>
</div>
<div class="col3">
<?php echo template::select('configConnectTimeout', $module::$connectTimeout , [
'label' => 'Durée du blocage',
'selected' => $this->getData(['config', 'connect', 'timeout'])
]); ?>
</div>
</div>
<div class="row">
<div class="col3 offset1">
<?php echo template::text('configAnalyticsId', [
'help' => 'Saisissez l\'ID de suivi.',
'label' => 'Google Analytics',
@ -382,21 +374,43 @@
'value' => $this->getData(['config', 'analyticsId'])
]); ?>
</div>
<div class="col3 offset1 verticalAlignBottom">
<?php echo template::button('configHead', [
<div class="col3 verticalAlignBottom">
<?php echo template::button('configScriptHead', [
'href' => helper::baseUrl() . 'config/script/head',
'value' => 'Script inséré dans head',
'value' => 'Script dans head',
'ico' => 'pencil'
]); ?>
</div>
<div class="col3 offset1 verticalAlignBottom">
<?php echo template::button('scriptBody', [
<div class="col3 verticalAlignBottom">
<?php echo template::button('ConfigScriptBody', [
'href' => helper::baseUrl() . 'config/script/body',
'value' => 'Script inséré dans body',
'value' => 'Script dans body',
'ico' => 'pencil'
]); ?>
</div>
</div>
<div class="row">
<div class="col3 offset1 verticalAlignBottom">
<?php echo template::checkbox('configConnectLog', true, 'Activer la journalisation', [
'checked' => $this->getData(['config', 'connect', 'log'])
]); ?>
</div>
<div class="col3">
<?php echo template::button('ConfigLogDownload', [
'href' => helper::baseUrl() . 'config/logDownload',
'value' => 'Téléchargement du journal',
'ico' => 'download'
]); ?>
</div>
<div class="col3">
<?php echo template::button('ConfigLogReset', [
'class' => 'buttonRed',
'href' => helper::baseUrl() . 'config/logReset',
'value' => 'Réinitialisation du journal',
'ico' => 'cancel'
]); ?>
</div>
</div>
</div>
</div>
</div>

3
core/module/install/ressource/defaultdata.php

@ -31,7 +31,8 @@ class init extends common {
],
"connect" => [
"timeout" => 360,
"attempt" => 3
"attempt" => 3,
'log' => false
]
],
'core' => [

29
core/module/user/user.php

@ -332,22 +332,17 @@ class user extends common {
// Soumission du formulaire
if($this->isPost()) {
$userId = $this->getInput('userLoginId', helper::FILTER_ID, true);
// Contrôle du time out
if ( $this->getData(['user',$userId,'connectTimeout']) + $this->getData(['config', 'connect', 'timeout']) > time() &&
$this->getData(['user',$userId,'connectFail']) > $this->getData(['config', 'connect', 'attempt']) ) {
$this->addOutput([
'notification' => 'Accès bloqué pour ' . $this->getData(['config', 'connect', 'timeout']) . ' minutes'
]);
}
// Contrôle du time out pas de vérification du mot de passe si le temps est dépassé.
// Connexion si les informations sont correctes
if(
if( $this->getData(['user',$userId,'connectTimeout']) + $this->getData(['config', 'connect', 'timeout']) < time() &&
$this->getData(['user',$userId,'connectFail']) < $this->getData(['config', 'connect', 'attempt']) &&
password_verify($this->getInput('userLoginPassword', helper::FILTER_STRING_SHORT, true), $this->getData(['user', $userId, 'password']))
AND $this->getData(['user', $userId, 'group']) >= self::GROUP_MEMBER
) {
$expire = $this->getInput('userLoginLongTime') ? strtotime("+1 year") : 0;
setcookie('ZWII_USER_ID', $userId, $expire, helper::baseUrl(false, false));
setcookie('ZWII_USER_PASSWORD', $this->getData(['user', $userId, 'password']), $expire, helper::baseUrl(false, false));
// Accès multiples avec le m$eme compte
// Accès multiples avec le même compte
$this->setData(['user',$userId,'accessCsrf',$_SESSION['csrf']]);
// Valeurs en sortie lorsque le site est en maintenance et que l'utilisateur n'est pas administrateur
if(
@ -363,7 +358,7 @@ class user extends common {
else {
// RAZ compteur échec connexion
$this->setData(['user',$userId,'connectFail',0 ]);
// Valeurs en sortie en cas de réussite
// Valeurs en sortie
$this->addOutput([
'notification' => 'Connexion réussie',
'redirect' => helper::baseUrl() . str_replace('_', '/', str_replace('__', '#', $this->getUrl(2))),
@ -377,9 +372,9 @@ class user extends common {
if ( is_array($this->getdata(['user',$userId])) ) {
$this->setData(['user',$userId,'connectFail',$this->getdata(['user',$userId,'connectFail']) + 1 ]);
}
// Mettre à jour le timer
// Mettre à jour le timer et notifier
if ( $this->getdata(['user',$userId,'connectFail']) > $this->getData(['config', 'connect', 'attempt'])) {
$notification = 'Trop de tentatives, accès bloqué durant ' . $this->getData(['config', 'connect', 'timeout']) . ' minutes.';
$notification = 'Trop de tentatives, accès bloqué durant ' . ($this->getData(['config', 'connect', 'timeout']) / 60) . ' minutes.';
// Ne pas incrémenter le timer si actif
if ($this->getData(['user',$userId,'connectTimeout']) + $this->getData(['config', 'connect', 'timeout']) < time() ) {
$this->setData(['user',$userId,'connectTimeout', time()]);
@ -387,6 +382,16 @@ class user extends common {
} else {
$notification = 'Identifiant ou mot de passe incorrect';
}
// Journalisation
$dataLog = strftime('%d/%m/%y',time()) . ';' . strftime('%R',time()) . ';' ;
$dataLog .= $_SERVER['REMOTE_ADDR'] . ';' ;
$dataLog .= $userId . ';' ;
$dataLog .= $this->getUrl() .';' ;
$dataLog .= 'échec de connexion' ;
$dataLog .= PHP_EOL;
if ($this->getData(['config','connect','log'])) {
file_put_contents(self::DATA_DIR . 'journal.log', $dataLog, FILE_APPEND);
}
// Valeurs en sortie
$this->addOutput([
'notification' => $notification

6
module/blog/view/index/index.php

@ -1,10 +1,10 @@
<?php if($module::$articles): ?>
<div class="row">
<div class="col12">
<?php foreach($module::$articles as $articleId => $article): ?>
<?php foreach($module::$articles as $articleId => $article): ?>
<div class="row rowArticle">
<div class="col3">
<?php
<?php
// Déterminer le nom de la miniature
$parts = explode('/',$article['picture']);
$thumb = str_replace ($parts[(count($parts)-1)],'mini_' . $parts[(count($parts)-1)], $article['picture']);
@ -31,7 +31,7 @@
<?php echo count($article['comment']); ?>
</a>
<?php echo template::ico('comment', 'left'); ?>
</div>
</div>
<div class="blogDate">
<i class="far fa-calendar-alt"></i>
<?php echo utf8_encode(strftime('%d %B %Y', $article['publishedOn'])); ?>

0
site/file/source/screenshot.png

Loading…
Cancel
Save