-
-
Notifications
You must be signed in to change notification settings - Fork 437
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Avoid session invalidation when changing session lifetime. (#546)
- Loading branch information
1 parent
14cf6fa
commit 447e27e
Showing
3 changed files
with
68 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,8 @@ class Mage_Core_Model_Session_Abstract_Varien extends Varien_Object | |
const VALIDATOR_HTTP_VIA_KEY = 'http_via'; | ||
const VALIDATOR_REMOTE_ADDR_KEY = 'remote_addr'; | ||
const VALIDATOR_SESSION_EXPIRE_TIMESTAMP = 'session_expire_timestamp'; | ||
const VALIDATOR_SESSION_RENEW_TIMESTAMP = 'session_renew_timestamp'; | ||
const VALIDATOR_SESSION_LIFETIME = 'session_lifetime'; | ||
const VALIDATOR_PASSWORD_CREATE_TIMESTAMP = 'password_create_timestamp'; | ||
const SECURE_COOKIE_CHECK_KEY = '_secure_cookie_check'; | ||
|
||
|
@@ -149,46 +151,46 @@ public function start($sessionName = null) | |
|
||
session_start(); | ||
|
||
if (Mage::app()->getFrontController()->getRequest()->isSecure() && empty($cookieParams['secure'])) { | ||
// secure cookie check to prevent MITM attack | ||
$secureCookieName = $sessionName . '_cid'; | ||
if (isset($_SESSION[self::SECURE_COOKIE_CHECK_KEY])) { | ||
$cookieValue = $cookie->get($secureCookieName); | ||
|
||
// Migrate old cookie from 'frontend' | ||
if ( ! $cookieValue | ||
&& $sessionName === \Mage_Core_Controller_Front_Action::SESSION_NAMESPACE | ||
&& $cookie->get('frontend_cid') | ||
&& ! $cookie->get($secureCookieName) | ||
) { | ||
$frontendValue = $cookie->get('frontend_cid'); | ||
$_COOKIE[$secureCookieName] = $frontendValue; | ||
$cookie->set($secureCookieName, $frontendValue); | ||
$cookie->delete('frontend_cid'); | ||
} | ||
Mage::dispatchEvent('session_before_renew_cookie', ['cookie' => $cookie]); | ||
|
||
if (!is_string($cookieValue) || $_SESSION[self::SECURE_COOKIE_CHECK_KEY] !== md5($cookieValue)) { | ||
session_regenerate_id(false); | ||
$sessionHosts = $this->getSessionHosts(); | ||
$currentCookieDomain = $cookie->getDomain(); | ||
foreach (array_keys($sessionHosts) as $host) { | ||
// Delete cookies with the same name for parent domains | ||
if (strpos($currentCookieDomain, $host) > 0) { | ||
$cookie->delete($this->getSessionName(), null, $host); | ||
} | ||
} | ||
$_SESSION = array(); | ||
} else { | ||
/** | ||
* Renew secure cookie expiration time if secure id did not change | ||
*/ | ||
$cookie->renew($secureCookieName, null, null, null, true, true); | ||
} | ||
// Secure cookie check to prevent MITM attack | ||
if (Mage::app()->getFrontController()->getRequest()->isSecure() && empty($cookieParams['secure'])) { | ||
$secureCookieName = $this->getSessionName() . '_cid'; | ||
$cookieValue = $cookie->get($secureCookieName); | ||
|
||
// Migrate old cookie from 'frontend' | ||
if ( ! $cookieValue | ||
&& $sessionName === \Mage_Core_Controller_Front_Action::SESSION_NAMESPACE | ||
&& $cookie->get('frontend_cid') | ||
) { | ||
$cookieValue = $cookie->get('frontend_cid'); | ||
$_COOKIE[$secureCookieName] = $cookieValue; | ||
$cookie->set($secureCookieName, $cookieValue); | ||
$cookie->delete('frontend_cid'); | ||
} | ||
|
||
// Set secure cookie check value in session if not yet set | ||
if (!isset($_SESSION[self::SECURE_COOKIE_CHECK_KEY])) { | ||
$checkId = Mage::helper('core')->getRandomString(16); | ||
$cookie->set($secureCookieName, $checkId, null, null, null, true, true); | ||
$_SESSION[self::SECURE_COOKIE_CHECK_KEY] = md5($checkId); | ||
$cookieValue = Mage::helper('core')->getRandomString(16); | ||
$cookie->set($secureCookieName, $cookieValue, null, null, null, true, true); | ||
$_SESSION[self::SECURE_COOKIE_CHECK_KEY] = md5($cookieValue); | ||
} | ||
// Renew secret check value cookie if it is valid | ||
else if (is_string($cookieValue) && $_SESSION[self::SECURE_COOKIE_CHECK_KEY] === md5($cookieValue)) { | ||
$cookie->renew($secureCookieName, null, null, null, true, true); | ||
} | ||
// Secure cookie check value is invalid, regenerate session | ||
else { | ||
session_regenerate_id(false); | ||
$sessionHosts = $this->getSessionHosts(); | ||
$currentCookieDomain = $cookie->getDomain(); | ||
foreach (array_keys($sessionHosts) as $host) { | ||
// Delete cookies with the same name for parent domains | ||
if (strpos($currentCookieDomain, $host) > 0) { | ||
$cookie->delete($this->getSessionName(), null, $host); | ||
} | ||
} | ||
$_SESSION = array(); | ||
} | ||
} | ||
|
||
|
@@ -467,7 +469,8 @@ public function validate() | |
|
||
// Refresh expire timestamp | ||
if ($this->useValidateSessionExpire()) { | ||
$_SESSION[self::VALIDATOR_KEY][self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] = time() + $this->getCookie()->getLifetime(); | ||
$_SESSION[self::VALIDATOR_KEY][self::VALIDATOR_SESSION_RENEW_TIMESTAMP] = time(); | ||
$_SESSION[self::VALIDATOR_KEY][self::VALIDATOR_SESSION_LIFETIME] = $this->getCookie()->getLifetime(); | ||
} | ||
} | ||
|
||
|
@@ -511,15 +514,18 @@ protected function _validate() | |
} | ||
|
||
if ($this->useValidateSessionExpire() | ||
&& isset($sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP]) | ||
&& $sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] < time() ) { | ||
&& isset($sessionData[self::VALIDATOR_SESSION_RENEW_TIMESTAMP]) | ||
&& isset($sessionData[self::VALIDATOR_SESSION_LIFETIME]) | ||
&& ((int)$sessionData[self::VALIDATOR_SESSION_RENEW_TIMESTAMP] + (int)$sessionData[self::VALIDATOR_SESSION_LIFETIME]) | ||
< time() | ||
) { | ||
return false; | ||
} | ||
if ($this->useValidateSessionPasswordTimestamp() | ||
&& isset($validatorData[self::VALIDATOR_PASSWORD_CREATE_TIMESTAMP]) | ||
&& isset($sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP]) | ||
&& isset($sessionData[self::VALIDATOR_SESSION_RENEW_TIMESTAMP]) | ||
&& $validatorData[self::VALIDATOR_PASSWORD_CREATE_TIMESTAMP] | ||
> $sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] - $this->getCookie()->getLifetime() | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
kiatng
Contributor
|
||
> $sessionData[self::VALIDATOR_SESSION_RENEW_TIMESTAMP] | ||
) { | ||
return false; | ||
} | ||
|
@@ -557,8 +563,6 @@ public function getValidatorData() | |
$parts[self::VALIDATOR_HTTP_USER_AGENT_KEY] = (string)$_SERVER['HTTP_USER_AGENT']; | ||
} | ||
|
||
$parts[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] = time() + $this->getCookie()->getLifetime(); | ||
|
||
if (isset($this->_data['visitor_data']['customer_id'])) { | ||
$parts[self::VALIDATOR_PASSWORD_CREATE_TIMESTAMP] = | ||
Mage::helper('customer')->getPasswordTimestamp($this->_data['visitor_data']['customer_id']); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Why did you remove the part that subtracts the cookie lifetime from the session expiration? This, combined with an existing Magento timestamp bug, resulted in me not being able to log into a newly created account until 4 hours had passed (that's my UTC offset)