diff options
Diffstat (limited to 'system/libraries/Session/drivers/Session_cookie.php')
-rw-r--r-- | system/libraries/Session/drivers/Session_cookie.php | 185 |
1 files changed, 67 insertions, 118 deletions
diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index d3d22d03a..566c40bd8 100644 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 1.0 @@ -165,6 +165,8 @@ class CI_Session_cookie extends CI_Session_driver { */ public $now; + // ------------------------------------------------------------------------ + /** * Default userdata keys * @@ -185,6 +187,15 @@ class CI_Session_cookie extends CI_Session_driver { protected $data_dirty = FALSE; /** + * Standardize newlines flag + * + * @var bool + */ + protected $_standardize_newlines; + + // ------------------------------------------------------------------------ + + /** * Initialize session driver object * * @return void @@ -209,9 +220,11 @@ class CI_Session_cookie extends CI_Session_driver { 'sess_time_to_update', 'time_reference', 'cookie_prefix', - 'encryption_key' + 'encryption_key', ); + $this->_standardize_newlines = (bool) config_item('standardize_newlines'); + foreach ($prefs as $key) { $this->$key = isset($this->_parent->params[$key]) @@ -227,7 +240,7 @@ class CI_Session_cookie extends CI_Session_driver { // Do we need encryption? If so, load the encryption class if ($this->sess_encrypt_cookie === TRUE) { - $this->CI->load->library('encrypt'); + $this->CI->load->library('encryption'); } // Check for database @@ -370,34 +383,45 @@ class CI_Session_cookie extends CI_Session_driver { return FALSE; } - $len = strlen($session) - 40; - - if ($len < 0) + if ($this->sess_encrypt_cookie === TRUE) { - log_message('debug', 'The session cookie was not signed.'); - return FALSE; + $session = $this->CI->encryption->decrypt($session); + if ($session === FALSE) + { + log_message('error', 'Session: Unable to decrypt the session cookie, possibly due to a HMAC mismatch.'); + return FALSE; + } } + else + { + if (($len = strlen($session) - 40) <= 0) + { + log_message('error', 'Session: The session cookie was not signed.'); + return FALSE; + } - // Check cookie authentication - $hmac = substr($session, $len); - $session = substr($session, 0, $len); + // Check cookie authentication + $hmac = substr($session, $len); + $session = substr($session, 0, $len); - if ($hmac !== hash_hmac('sha1', $session, $this->encryption_key)) - { - log_message('error', 'The session cookie data did not match what was expected.'); - $this->sess_destroy(); - return FALSE; - } + // Time-attack-safe comparison + $hmac_check = hash_hmac('sha1', $session, $this->encryption_key); + $diff = 0; + for ($i = 0; $i < 40; $i++) + { + $diff |= ord($hmac[$i]) ^ ord($hmac_check[$i]); + } - // Check for encryption - if ($this->sess_encrypt_cookie === TRUE) - { - // Decrypt the cookie data - $session = $this->CI->encrypt->decode($session); + if ($diff !== 0) + { + log_message('error', 'Session: HMAC mismatch. The session cookie data did not match what was expected.'); + $this->sess_destroy(); + return FALSE; + } } // Unserialize the session array - $session = $this->_unserialize($session); + $session = @unserialize($session); // Is the session data we unserialized an array with the correct format? if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity'])) @@ -472,7 +496,7 @@ class CI_Session_cookie extends CI_Session_driver { $row = $query->row(); if ( ! empty($row->user_data)) { - $custom_data = $this->_unserialize($row->user_data); + $custom_data = unserialize(trim($row->user_data)); if (is_array($custom_data)) { @@ -608,7 +632,7 @@ class CI_Session_cookie extends CI_Session_driver { if ( ! empty($userdata)) { // Serialize the custom data array so we can store it - $set['user_data'] = $this->_serialize($userdata); + $set['user_data'] = serialize($userdata); } // Reset query builder values. @@ -695,16 +719,28 @@ class CI_Session_cookie extends CI_Session_driver { ? array_intersect_key($this->userdata, $this->defaults) : $this->userdata; + // The Input class will do this and since we use HMAC verification, + // unless we standardize here as well, the hash won't match. + if ($this->_standardize_newlines) + { + foreach (array_keys($this->userdata) as $key) + { + $this->userdata[$key] = preg_replace('/(?:\r\n|[\r\n])/', PHP_EOL, $this->userdata[$key]); + } + } + // Serialize the userdata for the cookie - $cookie_data = $this->_serialize($cookie_data); + $cookie_data = serialize($cookie_data); if ($this->sess_encrypt_cookie === TRUE) { - $cookie_data = $this->CI->encrypt->encode($cookie_data); + $cookie_data = $this->CI->encryption->encrypt($cookie_data); + } + else + { + // Require message authentication + $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key); } - - // Require message authentication - $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key); $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); @@ -737,93 +773,6 @@ class CI_Session_cookie extends CI_Session_driver { // ------------------------------------------------------------------------ /** - * Serialize an array - * - * This function first converts any slashes found in the array to a temporary - * marker, so when it gets unserialized the slashes will be preserved - * - * @param mixed Data to serialize - * @return string Serialized data - */ - protected function _serialize($data) - { - if (is_array($data)) - { - array_walk_recursive($data, array(&$this, '_escape_slashes')); - } - elseif (is_string($data)) - { - $data = str_replace('\\', '{{slash}}', $data); - } - - return serialize($data); - } - - // ------------------------------------------------------------------------ - - /** - * Escape slashes - * - * This function converts any slashes found into a temporary marker - * - * @param string Value - * @param string Key - * @return void - */ - protected function _escape_slashes(&$val, $key) - { - if (is_string($val)) - { - $val = str_replace('\\', '{{slash}}', $val); - } - } - - // ------------------------------------------------------------------------ - - /** - * Unserialize - * - * This function unserializes a data string, then converts any - * temporary slash markers back to actual slashes - * - * @param mixed Data to unserialize - * @return mixed Unserialized data - */ - protected function _unserialize($data) - { - $data = @unserialize(trim($data)); - - if (is_array($data)) - { - array_walk_recursive($data, array(&$this, '_unescape_slashes')); - return $data; - } - - return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data; - } - - // ------------------------------------------------------------------------ - - /** - * Unescape slashes - * - * This function converts any slash markers back into actual slashes - * - * @param string Value - * @param string Key - * @return void - */ - protected function _unescape_slashes(&$val, $key) - { - if (is_string($val)) - { - $val = str_replace('{{slash}}', '\\', $val); - } - } - - // ------------------------------------------------------------------------ - - /** * Garbage collection * * This deletes expired session rows from database @@ -841,7 +790,7 @@ class CI_Session_cookie extends CI_Session_driver { $probability = ini_get('session.gc_probability'); $divisor = ini_get('session.gc_divisor'); - if ((mt_rand(0, $divisor) / $divisor) < $probability) + if (mt_rand(1, $divisor) <= $probability) { $expire = $this->now - $this->sess_expiration; $this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire); |