Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authordiosmosis <diosmosis@users.noreply.github.com>2019-06-17 07:03:06 +0300
committerGitHub <noreply@github.com>2019-06-17 07:03:06 +0300
commit824204a88d80b229df3708d1edcf5416eeb2ea44 (patch)
tree52b1cfd1bcb0e5961920094a9f69517d5cbefd55 /core
parentd61a9ea28a798f5598e2cb69c0ca6b3342b6c157 (diff)
Detect expired session use (#14502)
* Add INI config option and add tests. * Detect expired sessions. * Update config docs. * Apply review feedback including storing expiration in session fingerprint. * fixing tests. * fix unit tests * fix test
Diffstat (limited to 'core')
-rw-r--r--core/Date.php7
-rw-r--r--core/Session/SessionAuth.php26
-rw-r--r--core/Session/SessionFingerprint.php52
3 files changed, 76 insertions, 9 deletions
diff --git a/core/Date.php b/core/Date.php
index ec2a4dfd06..b91bbcd0ce 100644
--- a/core/Date.php
+++ b/core/Date.php
@@ -1070,7 +1070,12 @@ class Date
return new Exception($message . ": $dateString");
}
- private static function getNowTimestamp()
+ /**
+ * For tests.
+ * @return int|null
+ * @ignore
+ */
+ public static function getNowTimestamp()
{
return isset(self::$now) ? self::$now : time();
}
diff --git a/core/Session/SessionAuth.php b/core/Session/SessionAuth.php
index a64f042d05..835d3a2cb4 100644
--- a/core/Session/SessionAuth.php
+++ b/core/Session/SessionAuth.php
@@ -88,6 +88,11 @@ class SessionAuth implements Auth
$sessionFingerprint = new SessionFingerprint();
$userModel = $this->userModel;
+ if ($this->isExpiredSession($sessionFingerprint)) {
+ $sessionFingerprint->clear();
+ return $this->makeAuthFailure();
+ }
+
$userForSession = $sessionFingerprint->getUser();
if (empty($userForSession)) {
return $this->makeAuthFailure();
@@ -106,9 +111,7 @@ class SessionAuth implements Auth
return $this->makeAuthFailure();
}
- if ($sessionFingerprint->isRemembered()) {
- $this->updateSessionExpireTime();
- }
+ $this->updateSessionExpireTime($sessionFingerprint);
return $this->makeAuthSuccess($user);
}
@@ -178,12 +181,27 @@ class SessionAuth implements Auth
return $this->user['token_auth'];
}
- private function updateSessionExpireTime()
+ private function updateSessionExpireTime(SessionFingerprint $sessionFingerprint)
{
$sessionParams = session_get_cookie_params();
+ // we update the session cookie to make sure expired session cookies are not available client side...
$sessionCookieLifetime = Config::getInstance()->General['login_cookie_expire'];
setcookie(session_name(), session_id(), time() + $sessionCookieLifetime, $sessionParams['path'],
$sessionParams['domain'], $sessionParams['secure'], $sessionParams['httponly']);
+
+ // ...and we also update the expiration time stored server side so we can prevent expired sessions from being reused
+ $sessionFingerprint->updateSessionExpirationTime();
+ }
+
+ private function isExpiredSession(SessionFingerprint $sessionFingerprint)
+ {
+ $expirationTime = $sessionFingerprint->getExpirationTime();
+ if (empty($expirationTime)) {
+ return true;
+ }
+
+ $isExpired = Date::now()->getTimestampUTC() > $expirationTime;
+ return $isExpired;
}
}
diff --git a/core/Session/SessionFingerprint.php b/core/Session/SessionFingerprint.php
index e886ef9c8c..475bf6e004 100644
--- a/core/Session/SessionFingerprint.php
+++ b/core/Session/SessionFingerprint.php
@@ -9,6 +9,7 @@
namespace Piwik\Session;
+use Piwik\Config;
use Piwik\Date;
/**
@@ -73,19 +74,29 @@ class SessionFingerprint
public function initialize($userName, $isRemembered = false, $time = null)
{
+ $time = $time ?: Date::now()->getTimestampUTC();
$_SESSION[self::USER_NAME_SESSION_VAR_NAME] = $userName;
$_SESSION[self::SESSION_INFO_TWO_FACTOR_AUTH_VERIFIED] = 0;
$_SESSION[self::SESSION_INFO_SESSION_VAR_NAME] = [
- 'ts' => $time ?: Date::now()->getTimestampUTC(),
+ 'ts' => $time,
'remembered' => $isRemembered,
+ 'expiration' => $this->getExpirationTimeFromNow($time),
];
}
public function clear()
{
- unset($_SESSION[self::USER_NAME_SESSION_VAR_NAME]);
- unset($_SESSION[self::SESSION_INFO_SESSION_VAR_NAME]);
- unset($_SESSION[self::SESSION_INFO_TWO_FACTOR_AUTH_VERIFIED]);
+ if (isset($_SESSION[self::USER_NAME_SESSION_VAR_NAME])) { // may not be available during tests
+ unset($_SESSION[self::USER_NAME_SESSION_VAR_NAME]);
+ }
+
+ if (isset($_SESSION[self::SESSION_INFO_SESSION_VAR_NAME])) { // may not be available during tests
+ unset($_SESSION[self::SESSION_INFO_SESSION_VAR_NAME]);
+ }
+
+ if (isset($_SESSION[self::SESSION_INFO_TWO_FACTOR_AUTH_VERIFIED])) { // may not be available during tests
+ unset($_SESSION[self::SESSION_INFO_TWO_FACTOR_AUTH_VERIFIED]);
+ }
}
public function getSessionStartTime()
@@ -100,9 +111,42 @@ class SessionFingerprint
return $userInfo['ts'];
}
+ public function getExpirationTime()
+ {
+ $userInfo = $this->getUserInfo();
+ if (empty($userInfo)
+ || empty($userInfo['expiration'])
+ ) {
+ return null;
+ }
+
+ return $userInfo['expiration'];
+ }
+
public function isRemembered()
{
$userInfo = $this->getUserInfo();
return !empty($userInfo['remembered']);
}
+
+ public function updateSessionExpirationTime()
+ {
+ $_SESSION[self::SESSION_INFO_SESSION_VAR_NAME]['expiration'] = $this->getExpirationTimeFromNow();
+ }
+
+ private function getExpirationTimeFromNow($time = null)
+ {
+ $time = $time ?: Date::now()->getTimestampUTC();
+
+ $nonRememberedSessionExpireTime = Config::getInstance()->General['login_session_not_remembered_idle_timeout'];
+ $sessionCookieLifetime = Config::getInstance()->General['login_cookie_expire'];
+
+ if ($this->isRemembered()) {
+ $expireDuration = $sessionCookieLifetime;
+ } else {
+ $expireDuration = $nonRememberedSessionExpireTime;
+ }
+
+ return $time + $expireDuration;
+ }
}