From f6597c7cb90e9bfa96f01f5f78f98cd72696da55 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Nicolas=20L=C5=93uillet?= Date: Tue, 17 Sep 2013 14:48:16 +0200 Subject: [PATCH] fix bug #127: update session class --- inc/3rdparty/Session.class.php | 283 +++++++++++++++++++++++++-------- inc/poche/Poche.class.php | 1 + inc/poche/config.inc.php | 10 +- 3 files changed, 223 insertions(+), 71 deletions(-) diff --git a/inc/3rdparty/Session.class.php b/inc/3rdparty/Session.class.php index 3162f507..08126bad 100644 --- a/inc/3rdparty/Session.class.php +++ b/inc/3rdparty/Session.class.php @@ -1,136 +1,279 @@ $value) { - $_SESSION[$key] = $value; - } - if ($login==$login_test && $password==$password_test){ - // generate unique random number to sign forms (HMAC) - $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); - $_SESSION['info']=Session::_allInfos(); - $_SESSION['username']=$login; - // Set session expiration. - $_SESSION['expires_on']=time()+Session::$inactivity_timeout; - return true; + self::banInit(); + if (self::banCanLogin()) { + if ($login === $loginTest && $password === $passwordTest) { + self::banLoginOk(); + // Generate unique random number to sign forms (HMAC) + $_SESSION['uid'] = sha1(uniqid('', true).'_'.mt_rand()); + $_SESSION['ip'] = self::_allIPs(); + $_SESSION['username'] = $login; + // Set session expiration. + $_SESSION['expires_on'] = time() + self::$inactivityTimeout; + + foreach ($pValues as $key => $value) { + $_SESSION[$key] = $value; + } + + return true; + } + self::banLoginFailed(); } + return false; } - // Force logout + /** + * Unset SESSION variable to force logout + */ public static function logout() { - unset($_SESSION['uid'],$_SESSION['info'],$_SESSION['expires_on'],$_SESSION['tokens'], $_SESSION['login'], $_SESSION['pass'], $_SESSION['poche_user']); + unset($_SESSION['uid'], $_SESSION['ip'], $_SESSION['expires_on']); } - // Make sure user is logged in. + /** + * Make sure user is logged in. + * + * @return true|false True if user is logged in, false otherwise + */ public static function isLogged() { if (!isset ($_SESSION['uid']) - || $_SESSION['info']!=Session::_allInfos() - || time()>=$_SESSION['expires_on']){ - Session::logout(); + || (self::$disableSessionProtection === false + && $_SESSION['ip'] !== self::_allIPs()) + || time() >= $_SESSION['expires_on']) { + self::logout(); + return false; } // User accessed a page : Update his/her session expiration date. - $_SESSION['expires_on']=time()+Session::$inactivity_timeout; + $_SESSION['expires_on'] = time() + self::$inactivityTimeout; + if (!empty($_SESSION['longlastingsession'])) { + $_SESSION['expires_on'] += $_SESSION['longlastingsession']; + } + return true; } - // Returns a token. - public static function getToken() + /** + * Create a token, store it in SESSION and return it + * + * @param string $salt to prevent birthday attack + * + * @return string Token created + */ + public static function getToken($salt = '') { - if (!isset($_SESSION['tokens'])){ + if (!isset($_SESSION['tokens'])) { $_SESSION['tokens']=array(); } // We generate a random string and store it on the server side. - $rnd = sha1(uniqid('',true).'_'.mt_rand()); + $rnd = sha1(uniqid('', true).'_'.mt_rand().$salt); $_SESSION['tokens'][$rnd]=1; + return $rnd; } - // Tells if a token is ok. Using this function will destroy the token. - // return true if token is ok. + /** + * Tells if a token is ok. Using this function will destroy the token. + * + * @param string $token Token to test + * + * @return true|false True if token is correct, false otherwise + */ public static function isToken($token) { - if (isset($_SESSION['tokens'][$token])) - { + if (isset($_SESSION['tokens'][$token])) { unset($_SESSION['tokens'][$token]); // Token is used: destroy it. + return true; // Token is ok. } + return false; // Wrong token, or already used. } -} \ No newline at end of file + + /** + * Signal a failed login. Will ban the IP if too many failures: + */ + public static function banLoginFailed() + { + if (self::$banFile !== '') { + $ip = $_SERVER["REMOTE_ADDR"]; + $gb = $GLOBALS['IPBANS']; + + if (!isset($gb['FAILURES'][$ip])) { + $gb['FAILURES'][$ip] = 0; + } + $gb['FAILURES'][$ip]++; + if ($gb['FAILURES'][$ip] > (self::$banAfter - 1)) { + $gb['BANS'][$ip]= time() + self::$banDuration; + } + + $GLOBALS['IPBANS'] = $gb; + file_put_contents(self::$banFile, ""); + } + } + + /** + * Signals a successful login. Resets failed login counter. + */ + public static function banLoginOk() + { + if (self::$banFile !== '') { + $ip = $_SERVER["REMOTE_ADDR"]; + $gb = $GLOBALS['IPBANS']; + unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); + $GLOBALS['IPBANS'] = $gb; + file_put_contents(self::$banFile, ""); + } + } + + /** + * Ban init + */ + public static function banInit() + { + if (self::$banFile !== '') { + if (!is_file(self::$banFile)) { + file_put_contents(self::$banFile, "array(), 'BANS'=>array()), true).";\n?>"); + } + include self::$banFile; + } + } + + /** + * Checks if the user CAN login. If 'true', the user can try to login. + * + * @return boolean true if user is banned, false otherwise + */ + public static function banCanLogin() + { + if (self::$banFile !== '') { + $ip = $_SERVER["REMOTE_ADDR"]; + $gb = $GLOBALS['IPBANS']; + if (isset($gb['BANS'][$ip])) { + // User is banned. Check if the ban has expired: + if ($gb['BANS'][$ip] <= time()) { + // Ban expired, user can try to login again. + unset($gb['FAILURES'][$ip]); + unset($gb['BANS'][$ip]); + file_put_contents(self::$banFile, ""); + + return true; // Ban has expired, user can login. + } + + return false; // User is banned. + } + } + + return true; // User is not banned. + } +} diff --git a/inc/poche/Poche.class.php b/inc/poche/Poche.class.php index 9db4a034..2f0f7038 100644 --- a/inc/poche/Poche.class.php +++ b/inc/poche/Poche.class.php @@ -93,6 +93,7 @@ class Poche private function init() { Tools::initPhp(); + Session::$sessionName = 'poche'; Session::init(); if (isset($_SESSION['poche_user']) && $_SESSION['poche_user'] != array()) { diff --git a/inc/poche/config.inc.php b/inc/poche/config.inc.php index aaa26af8..9247c292 100755 --- a/inc/poche/config.inc.php +++ b/inc/poche/config.inc.php @@ -48,4 +48,12 @@ if (!ini_get('date.timezone') || !@date_default_timezone_set(ini_get('date.timez date_default_timezone_set('UTC'); } -$poche = new Poche(); \ No newline at end of file +$poche = new Poche(); + +#XSRF protection with token +if (!empty($_POST)) { + if (!Session::isToken($_POST['token'])) { + die(_('Wrong token')); + } + unset($_SESSION['tokens']); +} \ No newline at end of file -- 2.41.0