Index: branches/5.3.x/core/kernel/utility/http_query.php =================================================================== diff -u -N -r15483 -r15650 --- branches/5.3.x/core/kernel/utility/http_query.php (.../http_query.php) (revision 15483) +++ branches/5.3.x/core/kernel/utility/http_query.php (.../http_query.php) (revision 15650) @@ -1,6 +1,6 @@ Cookie = $this->AddVars($_COOKIE); + $cookie_hasher = $this->Application->makeClass('kCookieHasher'); + /* @var $cookie_hasher kCookieHasher */ + + $parsed_cookies = Array (); + + foreach ($_COOKIE as $cookie_name => $encrypted_value) { + $parsed_cookies[$cookie_name] = $cookie_hasher->decrypt($cookie_name, $encrypted_value); + } + + $this->Cookie = $this->AddVars($parsed_cookies); break; /*case 'E'; @@ -758,4 +767,4 @@ return !count($this->Get); } -} \ No newline at end of file +} Index: branches/5.3.x/core/install/english.lang =================================================================== diff -u -N -r15649 -r15650 --- branches/5.3.x/core/install/english.lang (.../english.lang) (revision 15649) +++ branches/5.3.x/core/install/english.lang (.../english.lang) (revision 15650) @@ -193,6 +193,7 @@ UGF0aCB0byBXZWJzaXRl UGVyZm9ybSBFeGFjdCBTZWFyY2g= Q29tbWVudHMgcGVyIHBhZ2U= + UGxhaW4gVGV4dCBDb29raWVz UmFuZG9tIFN0cmluZw== IlJlY3ljbGUgQmluIiBTZWN0aW9uSWQ= VXNlcm5hbWUgUmVxdWlyZWQgRHVyaW5nIFJlZ2lzdHJhdGlvbg== @@ -2211,4 +2212,4 @@ - + \ No newline at end of file Index: branches/5.3.x/core/install/install_data.sql =================================================================== diff -u -N -r15649 -r15650 --- branches/5.3.x/core/install/install_data.sql (.../install_data.sql) (revision 15649) +++ branches/5.3.x/core/install/install_data.sql (.../install_data.sql) (revision 15650) @@ -98,6 +98,7 @@ INSERT INTO SystemSettings VALUES(DEFAULT, 'SystemTagCache', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_prompt_syscache_enable', 'checkbox', NULL, NULL, 60.07, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SocketBlockingMode', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_prompt_socket_blocking_mode', 'checkbox', NULL, NULL, 60.08, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'RandomString', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_RandomString', 'text', '', '', 60.09, 0, 1, NULL); +INSERT INTO SystemSettings VALUES(DEFAULT, 'PlainTextCookies', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_PlainTextCookies', 'text', '', '', 60.10, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'EnableEmailLog', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_EnableEmailLog', 'radio', NULL, '1=la_Yes||0=la_No', 65.01, 0, 1, 'hint:la_config_EnableEmailLog'); INSERT INTO SystemSettings VALUES(DEFAULT, 'EmailLogRotationInterval', '2419200', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_EmailLogRotationInterval', 'select', NULL, '86400=la_opt_OneDay||604800=la_opt_OneWeek||1209600=la_opt_TwoWeeks||2419200=la_opt_OneMonth||7257600=la_opt_ThreeMonths||29030400=la_opt_OneYear||-1=la_opt_EmailLogKeepForever', 65.02, 0, 0, 'hint:la_config_EmailLogRotationInterval'); INSERT INTO SystemSettings VALUES(DEFAULT, 'SystemLogRotationInterval', '2419200', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_SystemLogRotationInterval', 'select', NULL, '86400=la_opt_OneDay||604800=la_opt_OneWeek||1209600=la_opt_TwoWeeks||2419200=la_opt_OneMonth||7257600=la_opt_ThreeMonths||29030400=la_opt_OneYear||-1=la_opt_SystemLogKeepForever', 65.03, 0, 1, 'hint:la_config_SystemLogRotationInterval'); @@ -1029,4 +1030,4 @@ INSERT INTO PromoBlockGroups VALUES (DEFAULT, 'Default Group', UNIX_TIMESTAMP(), '1', '7.00', '0.60', '1', 'fade', ''); INSERT INTO Modules VALUES ('Core', 'core/', 'adm', DEFAULT, 1, 1, '', 0, NULL, NULL); -INSERT INTO Modules VALUES ('In-Portal', 'core/', 'm', DEFAULT, 1, 0, '', 0, NULL, NULL); +INSERT INTO Modules VALUES ('In-Portal', 'core/', 'm', DEFAULT, 1, 0, '', 0, NULL, NULL); \ No newline at end of file Index: branches/5.3.x/core/kernel/session/session.php =================================================================== diff -u -N -r15580 -r15650 --- branches/5.3.x/core/kernel/session/session.php (.../session.php) (revision 15580) +++ branches/5.3.x/core/kernel/session/session.php (.../session.php) (revision 15650) @@ -1,6 +1,6 @@ CheckIfCookiesAreOn(); - if ($this->CookiesEnabled) $_COOKIE['cookies_on'] = 1; $this->Checkers = Array(); $this->InitStorage($special); @@ -383,14 +382,19 @@ $this->_autoGuessDomain(SERVER_NAME) ); + $cookie_hasher = $this->Application->makeClass('kCookieHasher'); + /* @var $cookie_hasher kCookieHasher */ + + $encrypted_value = $cookie_hasher->encrypt($name, $value); + foreach ($old_style_domains as $old_style_domain) { if ($this->CookieDomain != $old_style_domain) { // new style cookie domain -> delete old style cookie to prevent infinite redirect - setcookie($name, $value, adodb_mktime() - 3600, $this->CookiePath, $old_style_domain, $this->CookieSecure); + setcookie($name, $encrypted_value, adodb_mktime() - 3600, $this->CookiePath, $old_style_domain, $this->CookieSecure); } } - setcookie($name, $value, $expires, $this->CookiePath, $this->CookieDomain, $this->CookieSecure); + setcookie($name, $encrypted_value, $expires, $this->CookiePath, $this->CookieDomain, $this->CookieSecure); } function Check() @@ -653,14 +657,12 @@ { $this->SetCookie($this->CookieName, $this->SID, $this->Expiration); $this->SetCookie($this->CookieName.'_live', $this->SID); - $_COOKIE[$this->CookieName] = $this->SID; // for compatibility with in-portal } function RemoveSessionCookie() { $this->SetCookie($this->CookieName, ''); $this->SetCookie($this->CookieName.'_live', ''); - $_COOKIE[$this->CookieName] = null; // for compatibility with in-portal } /** @@ -1130,4 +1132,4 @@ return $ret; } -} \ No newline at end of file +} Index: branches/5.3.x/core/kernel/application.php =================================================================== diff -u -N -r15581 -r15650 --- branches/5.3.x/core/kernel/application.php (.../application.php) (revision 15581) +++ branches/5.3.x/core/kernel/application.php (.../application.php) (revision 15650) @@ -1,6 +1,6 @@ registerClass('kHTTPQuery', KERNEL_PATH . '/utility/http_query.php', 'HTTPQuery'); // session + $this->registerClass('kCookieHasher', KERNEL_PATH . '/utility/cookie_hasher.php'); $this->registerClass('Session', KERNEL_PATH . '/session/session.php'); $this->registerClass('SessionStorage', KERNEL_PATH . '/session/session_storage.php'); $this->registerClass('InpSession', KERNEL_PATH . '/session/inp_session.php', 'Session'); @@ -3023,4 +3024,4 @@ { $this->_logger->delete($unique_id, $storage_medium); } -} \ No newline at end of file +} Index: branches/5.3.x/core/kernel/utility/cookie_hasher.php =================================================================== diff -u -N --- branches/5.3.x/core/kernel/utility/cookie_hasher.php (revision 0) +++ branches/5.3.x/core/kernel/utility/cookie_hasher.php (revision 15650) @@ -0,0 +1,177 @@ +Application->ConfigValue('RandomString'); + } + + $this->_config = Array ( + 'secret' => substr($secret, 0, 32), // used cipher only allows 256bit (or less) key length + 'cipher' => MCRYPT_RIJNDAEL_256, + 'mode' => MCRYPT_MODE_CBC, + 'vector' => static::_vector(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC) + ); + + $plain_text_cookies = (string)$this->Application->ConfigValue('PlainTextCookies'); + + if ( $plain_text_cookies ) { + $plain_text_cookies = array_filter(array_map('trim', explode(',', $plain_text_cookies))); + $this->_plainTextCookies = array_unique(array_merge($this->_plainTextCookies, $plain_text_cookies)); + } + } + + /** + * Determines if cookie should be processed or passed through as is + * + * @param string $cookie_name + * @return bool + * @access protected + */ + protected function _isPassThrough($cookie_name) + { + return in_array($cookie_name, $this->_plainTextCookies); + } + + /** + * Generates encryption vector and returns it + * + * @param string $cipher + * @param string $mode + * @return string + * @access protected + */ + protected static function _vector($cipher, $mode) + { + if ( static::$_vector ) { + return static::$_vector; + } + + $size = static::_vectorSize($cipher, $mode); + + return static::$_vector = mcrypt_create_iv($size, MCRYPT_DEV_URANDOM); + } + + /** + * Returns vector size for given cipher and encryption mode + * + * @param string $cipher + * @param string $mode + * @return int + * @access protected + */ + protected static function _vectorSize($cipher, $mode) + { + return mcrypt_get_iv_size($cipher, $mode); + } + + /** + * Encrypts a cookie + * + * @param string $cookie_name + * @param mixed $plain_value + * @return string + * @access public + */ + public function encrypt($cookie_name, $plain_value) + { + if ( $this->_isPassThrough($cookie_name) ) { + return $plain_value; + } + + $cipher = $this->_config['cipher']; + $secret = $this->_config['secret']; + $mode = $this->_config['mode']; + $vector = $this->_config['vector']; + + $data = Array ($cookie_name => $plain_value); + $encrypted = mcrypt_encrypt($cipher, $secret, serialize($data), $mode, $vector); + + return base64_encode($encrypted) . base64_encode($vector); + } + + /** + * Decrypts a cookie + * + * @param string $cookie_name + * @param string $encrypted_value + * @return mixed + * @access public + */ + public function decrypt($cookie_name, $encrypted_value) + { + if ( $this->_isPassThrough($cookie_name) ) { + return $encrypted_value; + } + + $cipher = $this->_config['cipher']; + $secret = $this->_config['secret']; + $mode = $this->_config['mode']; + + $vectorSize = strlen(base64_encode(str_repeat(' ', static::_vectorSize($cipher, $mode)))); + $vector = $this->_safeBase64Decode(substr($encrypted_value, -$vectorSize)); + $data = $this->_safeBase64Decode(substr($encrypted_value, 0, -$vectorSize)); + + if ( $vector === false || $data === false ) { + // non-encrypted or malformed cookie value given + return ''; + } + + // non-serialized array is decrypted in case of decrypting old cookies after a secret change + $decrypted = trim(mcrypt_decrypt($cipher, $secret, $data, $mode, $vector)); + $data = kUtil::IsSerialized($decrypted) ? unserialize($decrypted) : Array (); + + // check if cookie value was actually copied from other cookie + return isset($data[$cookie_name]) ? $data[$cookie_name] : ''; + } + + /** + * Safely decodes base64-encoded string + * + * @param string $encoded_string + * @return string|bool + * @access protected + */ + protected function _safeBase64Decode($encoded_string) + { + $decoded_string = base64_decode($encoded_string); + + if ( (string)base64_encode($decoded_string) !== (string)$encoded_string ) { + return false; + } + + return $decoded_string; + } +} Index: branches/5.3.x/core/install/upgrades.sql =================================================================== diff -u -N -r15649 -r15650 --- branches/5.3.x/core/install/upgrades.sql (.../upgrades.sql) (revision 15649) +++ branches/5.3.x/core/install/upgrades.sql (.../upgrades.sql) (revision 15650) @@ -2885,3 +2885,5 @@ WHERE (DisplayOrder BETWEEN 60.04 AND 60.10) AND (ModuleOwner = 'In-Portal') AND (Section = 'in-portal:configure_advanced'); INSERT INTO SystemSettings VALUES(DEFAULT, 'RandomString', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_RandomString', 'text', '', '', 60.09, 0, 1, NULL); + +INSERT INTO SystemSettings VALUES(DEFAULT, 'PlainTextCookies', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_PlainTextCookies', 'text', '', '', 60.10, 0, 1, NULL);