Index: branches/5.0.x/core/kernel/session/session.php =================================================================== diff -u -r12369 -r12399 --- branches/5.0.x/core/kernel/session/session.php (.../session.php) (revision 12369) +++ branches/5.0.x/core/kernel/session/session.php (.../session.php) (revision 12399) @@ -1,6 +1,6 @@ SessionTimeout = $new_timeout; } + /** + * Calculates browser signature + * + * @return string + */ + function _getBrowserSignature() + { + $signature_parts = Array( + 'HTTP_USER_AGENT', 'SERVER_PROTOCOL', + 'HTTP_ACCEPT_CHARSET', 'HTTP_ACCEPT_ENCODING', 'HTTP_ACCEPT_LANGUAGE' + ); + + $ret = ''; + + foreach ($signature_parts as $signature_part) { + if (array_key_exists($signature_part, $_SERVER)) { + $ret .= '&|&' . $_SERVER[$signature_part]; + } + } + + return md5( substr($ret, 3) ); + } + function StoreSession(&$session, $additional_fields = Array()) { if (defined('IS_INSTALL') && IS_INSTALL && !$this->Application->TableFound($this->TableName)) { @@ -118,7 +141,8 @@ $fields_hash = Array ( $this->IDField => $session->SID, - $this->TimestampField => $session->Expiration + $this->TimestampField => $session->Expiration, + 'BrowserSignature' => $this->_getBrowserSignature(), ); // default values + additional values + values set during this script run @@ -152,16 +176,29 @@ function LocateSession($sid) { - $query = ' SELECT * FROM '.$this->TableName.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($sid); - $result = $this->Conn->GetRow($query); - + $sql = 'SELECT * + FROM ' . $this->TableName . ' + WHERE ' . $this->IDField . ' = ' . $this->Conn->qstr($sid); + $result = $this->Conn->GetRow($sql); + if ($result === false) { return false; } + // perform security checks to ensure, that session is used by it's creator + if ($this->Application->ConfigValue('SessionBrowserSignatureCheck') && ($result['BrowserSignature'] != $this->_getBrowserSignature())) { + return false; + } + + if ($this->Application->ConfigValue('SessionIPAddressCheck') && ($result['IpAddress'] != $_SERVER['REMOTE_ADDR'])) { + // most secure, except for cases where NAT (Network Address Translation) + // is used and two or more computers can have same IP address + return false; + } + $this->DirectVars = $result; - $this->Expiration = $result[$this->TimestampField]; + return true; } @@ -569,26 +606,34 @@ } } + /** + * This is redirect from https to http or via versa + * + * @return bool + */ function IsHTTPSRedirect() { - $http_referer = getArrayValue($_SERVER, 'HTTP_REFERER'); + $http_referer = array_key_exists('HTTP_REFERER', $_SERVER) ? $_SERVER['HTTP_REFERER'] : false; + return ( ( PROTOCOL == 'https://' && preg_match('#http:\/\/#', $http_referer) ) || ( PROTOCOL == 'http://' && preg_match('#https:\/\/#', $http_referer) ) ); } - function CheckReferer($for_cookies=0) + /** + * Helper method for detecting cookie availability + * + * @return bool + */ + function _checkCookieReferer() { - if (!$for_cookies) { - if ( !$this->Application->ConfigValue('SessionReferrerCheck') || $_SERVER['REQUEST_METHOD'] != 'POST') { - return true; - } - } - $path = preg_replace('/admin[\/]{0,1}$/', '', $this->CookiePath); // removing /admin for compatability with in-portal (in-link/admin/add_link.php) + // removing /admin for compatability with in-portal (in-link/admin/add_link.php) + $path = preg_replace('/admin[\/]{0,1}$/', '', $this->CookiePath); $reg = '#^'.preg_quote(PROTOCOL.ltrim($this->CookieDomain, '.').$path).'#'; - return preg_match($reg, getArrayValue($_SERVER, 'HTTP_REFERER') ) || (defined('IS_POPUP') && IS_POPUP); + + return preg_match($reg, getArrayValue($_SERVER, 'HTTP_REFERER') ); } function CheckIfCookiesAreOn() @@ -612,7 +657,7 @@ if (!$cookies_on || $this->IsHTTPSRedirect()) { //If referer is our server, but we don't have our cookies_on, it's definetly off $is_install = defined('IS_INSTALL') && IS_INSTALL; - if (!$is_install && $this->CheckReferer(1) && !$this->Application->GetVar('admin') && !$this->IsHTTPSRedirect()) { + if (!$is_install && $this->_checkCookieReferer() && !$this->Application->GetVar('admin') && !$this->IsHTTPSRedirect()) { $this->CookiesEnabled = false; } else { @@ -642,19 +687,14 @@ function Check() { - // we should check referer if cookies are disabled, and in combined mode - // auto mode would detect cookies, get only mode would turn it off - so we would get here - // and we don't care about referal in cookies only mode + // don't check referer here, because it doesn't provide any security option and can be easily falsified + + $sid = $this->GetPassedSIDValue(); - if ( $this->Mode != smCOOKIES_ONLY && (!$this->CookiesEnabled || $this->Mode == smCOOKIES_AND_GET) ) { - if (!$this->CheckReferer()) - return false; + if (empty($sid)) { + return false; } - $sid = $this->GetPassedSIDValue(); - - if (empty($sid)) return false; - //try to load session by sid, if everything is fine $result = $this->LoadSession($sid); @@ -666,22 +706,24 @@ function LoadSession($sid) { if( $this->Storage->LocateSession($sid) ) { - //if we have session with such SID - get its expiration + // if we have session with such SID - get its expiration $this->Expiration = $this->Storage->GetExpiration(); - //If session has expired + // If session has expired if ($this->Expiration < adodb_mktime()) { $this->Destroy(); // when Destory methods calls SetSession inside and new session get created return $this->SessionSet; } - //Otherwise it's ok + // Otherwise it's ok return true; } - else //fake or deleted due to expiration SID + else { + // fake or deleted due to expiration SID return false; + } } function GetPassedSIDValue($use_cache = 1) @@ -973,18 +1015,20 @@ } $this->Application->Debugger->dumpVars($session_data); - // dump real keys - $data_keys = array_keys($session_data); - $optional_keys = array_keys($this->OptionalData); - $real_keys = array_diff($data_keys, $optional_keys); - - if ($real_keys) { - $ret = ''; - foreach ($real_keys as $real_key) { - $ret .= '[' . $real_key . '] = [' . $session_data[$real_key] . ']
'; + if (!$this->RecallVar('admin')) { + // dump real keys (only for front-end) + $data_keys = array_keys($session_data); + $optional_keys = array_keys($this->OptionalData); + $real_keys = array_diff($data_keys, $optional_keys); + + if ($real_keys) { + $ret = ''; + foreach ($real_keys as $real_key) { + $ret .= '[' . $real_key . '] = [' . $session_data[$real_key] . ']
'; + } + + $this->Application->Debugger->appendHTML('Real Keys:
' . $ret); } - - $this->Application->Debugger->appendHTML('Real Keys:
' . $ret); } }