diff options
author | Dries Buytaert <dries@buytaert.net> | 2010-11-05 19:05:02 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2010-11-05 19:05:02 +0000 |
commit | e920fe34ef16d30af0f4fb8e33b565e572ab30c8 (patch) | |
tree | 9282e247144413df5d94ddfa4863a02a9514672b /includes | |
parent | 5f550ab80ca279706fd1681920e45172ab23748b (diff) | |
download | brdo-e920fe34ef16d30af0f4fb8e33b565e572ab30c8.tar.gz brdo-e920fe34ef16d30af0f4fb8e33b565e572ab30c8.tar.bz2 |
- Patch #575280 by mfb, carlos8f, chx, bleen18: impersonation when an https session exists.
Diffstat (limited to 'includes')
-rw-r--r-- | includes/bootstrap.inc | 65 | ||||
-rw-r--r-- | includes/session.inc | 29 | ||||
-rw-r--r-- | includes/update.inc | 2 |
3 files changed, 55 insertions, 41 deletions
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 6f695814a..e83832d5b 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -2134,15 +2134,7 @@ function _drupal_bootstrap_database() { // The user agent header is used to pass a database prefix in the request when // running tests. However, for security reasons, it is imperative that we // validate we ourselves made the request. - if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);/", $_SERVER['HTTP_USER_AGENT'], $matches)) { - if (!drupal_valid_test_ua($_SERVER['HTTP_USER_AGENT'])) { - header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden'); - exit; - } - - // The first part of the user agent is the prefix itself. - $test_prefix = $matches[1]; - + if ($test_prefix = drupal_valid_test_ua()) { // Set the test run id for use in other parts of Drupal. $test_info = &$GLOBALS['drupal_test_info']; $test_info['test_run_id'] = $test_prefix; @@ -2221,22 +2213,40 @@ function drupal_get_bootstrap_phase() { } /** - * Validate the HMAC and timestamp of a user agent header from simpletest. + * Checks the current User-Agent string to see if this is an internal request + * from SimpleTest. If so, returns the test prefix for this test. + * + * @return + * Either the simpletest prefix (the string "simpletest" followed by any + * number of digits) or FALSE if the user agent does not contain a valid + * HMAC and timestamp. */ -function drupal_valid_test_ua($user_agent) { +function drupal_valid_test_ua() { global $drupal_hash_salt; + // No reason to reset this. + static $test_prefix; + + if (isset($test_prefix)) { + return $test_prefix; + } - list($prefix, $time, $salt, $hmac) = explode(';', $user_agent); - $check_string = $prefix . ';' . $time . ';' . $salt; - // We use the salt from settings.php to make the HMAC key, since - // the database is not yet initialized and we can't access any Drupal variables. - // The file properties add more entropy not easily accessible to others. - $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc'; - $key = $drupal_hash_salt . filectime($filepath) . fileinode($filepath); - $time_diff = REQUEST_TIME - $time; - // Since we are making a local request a 5 second time window is allowed, - // and the HMAC must match. - return ($time_diff >= 0) && ($time_diff <= 5) && ($hmac == drupal_hmac_base64($check_string, $key)); + if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);(.+);(.+);(.+)$/", $_SERVER['HTTP_USER_AGENT'], $matches)) { + list(, $prefix, $time, $salt, $hmac) = $matches; + $check_string = $prefix . ';' . $time . ';' . $salt; + // We use the salt from settings.php to make the HMAC key, since + // the database is not yet initialized and we can't access any Drupal variables. + // The file properties add more entropy not easily accessible to others. + $key = $drupal_hash_salt . filectime(__FILE__) . fileinode(__FILE__); + $time_diff = REQUEST_TIME - $time; + // Since we are making a local request a 5 second time window is allowed, + // and the HMAC must match. + if ($time_diff >= 0 && $time_diff <= 5 && $hmac == drupal_hmac_base64($check_string, $key)) { + $test_prefix = $prefix; + return $test_prefix; + } + } + + return FALSE; } /** @@ -2250,13 +2260,12 @@ function drupal_generate_test_ua($prefix) { // We use the salt from settings.php to make the HMAC key, since // the database is not yet initialized and we can't access any Drupal variables. // The file properties add more entropy not easily accessible to others. - $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc'; - $key = $drupal_hash_salt . filectime($filepath) . fileinode($filepath); + $key = $drupal_hash_salt . filectime(__FILE__) . fileinode(__FILE__); } - // Generate a moderately secure HMAC based on the database credentials. - $salt = uniqid('', TRUE); - $check_string = $prefix . ';' . time() . ';' . $salt; - return $check_string . ';' . drupal_hmac_base64($check_string, $key); + // Generate a moderately secure HMAC based on the database credentials. + $salt = uniqid('', TRUE); + $check_string = $prefix . ';' . time() . ';' . $salt; + return $check_string . ';' . drupal_hmac_base64($check_string, $key); } /** diff --git a/includes/session.inc b/includes/session.inc index 412db118a..c23c23e1c 100644 --- a/includes/session.inc +++ b/includes/session.inc @@ -88,7 +88,10 @@ function _drupal_session_read($sid) { // a HTTPS session or we are about to log in so we check the sessions table // for an anonymous session with the non-HTTPS-only cookie. if ($is_https) { - $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.ssid = :ssid", array(':ssid' => $sid))->fetchObject(); + // Ensure that an empty secure session ID cannot be selected. + if ($sid) { + $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.ssid = :ssid", array(':ssid' => $sid))->fetchObject(); + } if (!$user) { if (isset($_COOKIE[$insecure_session_name])) { $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid AND s.uid = 0", array( @@ -180,21 +183,23 @@ function _drupal_session_write($sid, $value) { 'timestamp' => REQUEST_TIME, ); - // The "secure pages" setting allows a site to simultaneously use both - // secure and insecure session cookies. If enabled and both cookies are - // presented then use both keys. If not enabled but on HTTPS then use the - // PHP session id as 'ssid'. If on HTTP then use the PHP session id as - // 'sid'. + // Use the session ID as 'sid' and an empty string as 'ssid' by default. + // _drupal_session_read() does not allow empty strings so that's a safe + // default. + $key = array('sid' => $sid, 'ssid' => ''); + // On HTTPS connections, use the session ID as both 'sid' and 'ssid'. if ($is_https) { $key['ssid'] = $sid; - $insecure_session_name = substr(session_name(), 1); - if (variable_get('https', FALSE) && isset($_COOKIE[$insecure_session_name])) { - $key['sid'] = $_COOKIE[$insecure_session_name]; + // The "secure pages" setting allows a site to simultaneously use both + // secure and insecure session cookies. If enabled and both cookies are + // presented then use both keys. + if (variable_get('https', FALSE)) { + $insecure_session_name = substr(session_name(), 1); + if (isset($_COOKIE[$insecure_session_name])) { + $key['sid'] = $_COOKIE[$insecure_session_name]; + } } } - else { - $key['sid'] = $sid; - } db_merge('sessions') ->key($key) diff --git a/includes/update.inc b/includes/update.inc index c352cf8a3..5fdc16981 100644 --- a/includes/update.inc +++ b/includes/update.inc @@ -701,7 +701,7 @@ function update_fix_d7_requirements() { } // Add ssid column and index. - db_add_field('sessions', 'ssid', array('description' => "Secure session ID. The value is generated by PHP's Session API.", 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => '')); + db_add_field('sessions', 'ssid', array('description' => "Secure session ID. The value is generated by Drupal's session handlers.", 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => '')); db_add_index('sessions', 'ssid', array('ssid')); // Drop existing primary key. db_drop_primary_key('sessions'); |