diff options
-rw-r--r-- | includes/bootstrap.inc | 30 | ||||
-rw-r--r-- | modules/simpletest/tests/bootstrap.test | 18 |
2 files changed, 36 insertions, 12 deletions
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index c3f553793..da33a88f2 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -347,11 +347,6 @@ function conf_path($require_settings = TRUE, $reset = FALSE) { } $uri = explode('/', $_SERVER['SCRIPT_NAME'] ? $_SERVER['SCRIPT_NAME'] : $_SERVER['SCRIPT_FILENAME']); - if (strpos($_SERVER['HTTP_HOST'], '/') !== FALSE || strpos($_SERVER['HTTP_HOST'], '\\') !== FALSE) { - // A HTTP_HOST containing slashes may be an attack and is invalid. - header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request'); - exit; - } $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.'))))); for ($i = count($uri) - 1; $i > 0; $i--) { for ($j = count($server); $j > 0; $j--) { @@ -386,6 +381,21 @@ function drupal_initialize_variables() { } /** + * Validate that $_SERVER['HTTP_HOST'] is safe. + * + * As $_SERVER['HTTP_HOST'] is user input, ensure it only contains characters + * allowed in hostnames. See RFC 952 (and RFC 2181). $_SERVER['HTTP_HOST'] is + * lowercased. + * + * @return + * TRUE if only containing valid characters, or FALSE otherwise. + */ +function drupal_valid_http_host() { + $_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']); + return preg_match('/^\[?(?:[a-z0-9-:\]_]+\.?)+$/', $_SERVER['HTTP_HOST']); +} + +/** * Loads the configuration and sets the base URL, cookie domain, and * session name correctly. */ @@ -396,6 +406,12 @@ function conf_init() { global $databases, $db_prefix, $cookie_domain, $conf, $installed_profile, $update_free_access; $conf = array(); + if (!drupal_valid_http_host()) { + // HTTP_HOST is invalid, e.g. if containing slashes it may be an attack. + header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request'); + exit; + } + if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) { include_once DRUPAL_ROOT . '/' . conf_path() . '/settings.php'; } @@ -414,9 +430,7 @@ function conf_init() { // Create base URL $base_root = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; - // As $_SERVER['HTTP_HOST'] is user input, ensure it only contains - // characters allowed in hostnames. - $base_url = $base_root .= '://' . preg_replace('/[^a-z0-9-:._]/i', '', $_SERVER['HTTP_HOST']); + $base_url = $base_root .= '://' . $_SERVER['HTTP_HOST']; // $_SERVER['SCRIPT_NAME'] can, in contrast to $_SERVER['PHP_SELF'], not // be modified by a visitor. diff --git a/modules/simpletest/tests/bootstrap.test b/modules/simpletest/tests/bootstrap.test index 8be13aaeb..638d6b89f 100644 --- a/modules/simpletest/tests/bootstrap.test +++ b/modules/simpletest/tests/bootstrap.test @@ -8,8 +8,8 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase { */ function getInfo() { return array( - 'name' => t('IP address test'), - 'description' => t('Get the IP address from the current visitor from the server variables.'), + 'name' => t('IP address and HTTP_HOST test'), + 'description' => t('Get the IP address from the current visitor from the server variables, check hostname validation.'), 'group' => t('Bootstrap') ); } @@ -42,9 +42,9 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase { } /** - * testIPAddress + * test IP Address and hostname */ - function testIPAddress() { + function testIPAddressHost() { // Test the normal IP address. $this->assertTrue( ip_address(true) == $this->remote_ip, @@ -80,6 +80,16 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase { ip_address(true) == $this->cluster_ip, t('Cluster environment got cluster client IP') ); + $_SERVER['HTTP_HOST'] = 'security/.drupal.org:80'; + $this->assertFalse(drupal_valid_http_host(), t('HTTP_HOST with / is invalid')); + $_SERVER['HTTP_HOST'] = 'security\\.drupal.org:80'; + $this->assertFalse(drupal_valid_http_host(), t('HTTP_HOST with \\ is invalid')); + $_SERVER['HTTP_HOST'] = 'security<.drupal.org:80'; + $this->assertFalse(drupal_valid_http_host(), t('HTTP_HOST with < is invalid')); + $_SERVER['HTTP_HOST'] = 'security..drupal.org:80'; + $this->assertFalse(drupal_valid_http_host(), t('HTTP_HOST with .. is invalid')); + $_SERVER['HTTP_HOST'] = '[::1]:80'; // IPv6 loopback address + $this->assertTrue(drupal_valid_http_host(), t('HTTP_HOST containing IPv6 loopback is valid')); } } |