diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index ff73df633c..e1de4fee1d 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -722,8 +722,8 @@ function drupal_environment_initialize() {
/**
* Validates that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
*
- * @return
- * TRUE if only containing valid characters, or FALSE otherwise.
+ * @return bool
+ * TRUE if only containing valid characters, or FALSE otherwise.
*/
function drupal_valid_http_host($host) {
// Limit the length of the host name to 1000 bytes to prevent DoS attacks with
@@ -2651,6 +2651,18 @@ function _drupal_bootstrap_configuration() {
// Initialize the configuration, including variables from settings.php.
drupal_settings_initialize();
+ // Check trusted HTTP Host headers to protect against header attacks.
+ if (PHP_SAPI !== 'cli') {
+ $host_patterns = variable_get('trusted_host_patterns', array());
+ if (!empty($host_patterns)) {
+ if (!drupal_check_trusted_hosts($_SERVER['HTTP_HOST'], $host_patterns)) {
+ header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
+ print 'The provided host name is not valid for this server.';
+ exit;
+ }
+ }
+ }
+
// Sanitize unsafe keys from the request.
DrupalRequestSanitizer::sanitize();
}
@@ -3879,3 +3891,33 @@ function drupal_clear_opcode_cache($filepath) {
@apc_delete_file($filepath);
}
}
+
+/**
+ * Check trusted HTTP Host headers to protect against header injection attacks.
+ *
+ * @param string $host
+ * The host name.
+ * @param array $host_patterns
+ * The array of trusted host patterns.
+ *
+ * @return bool
+ * TRUE if the host is trusted, FALSE otherwise.
+ */
+function drupal_check_trusted_hosts($host, array $host_patterns) {
+ if (!empty($host_patterns)) {
+ // Trim and remove the port number from host, host is lowercase as per
+ // RFC 952/2181.
+ $host = strtolower(preg_replace('/:\d+$/', '', trim($host)));
+
+ foreach ($host_patterns as $pattern) {
+ $pattern = sprintf('{%s}i', $pattern);
+ if (preg_match($pattern, $host)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/modules/system/system.install b/modules/system/system.install
index d6707bedf7..aaf883f632 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -520,6 +520,27 @@ function system_requirements($phase) {
}
}
+ // See if trusted hostnames have been configured, and warn the user if they
+ // are not set.
+ if ($phase == 'runtime') {
+ $trusted_host_patterns = variable_get('trusted_host_patterns', array());
+ if (empty($trusted_host_patterns)) {
+ $requirements['trusted_host_patterns'] = array(
+ 'title' => $t('Trusted Host Settings'),
+ 'value' => $t('Not enabled'),
+ 'description' => $t('The trusted_host_patterns setting is not configured in settings.php. This can lead to security vulnerabilities. It is highly recommended that you configure this. See Protecting against HTTP HOST Header attacks for more information.', array('@url' => 'https://www.drupal.org/node/1992030')),
+ 'severity' => REQUIREMENT_ERROR,
+ );
+ }
+ else {
+ $requirements['trusted_host_patterns'] = array(
+ 'title' => $t('Trusted Host Settings'),
+ 'value' => $t('Enabled'),
+ 'description' => $t('The trusted_host_patterns setting is set to allow %trusted_host_patterns', array('%trusted_host_patterns' => implode(', ', $trusted_host_patterns))),
+ );
+ }
+ }
+
return $requirements;
}
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index bf367b2089..2ac652e09c 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -634,6 +634,42 @@ $conf['404_fast_html'] = '