diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 6495229..fa6570e 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -206,6 +206,9 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface { * from disk. Defaults to TRUE. * * @return static + * + * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException + * In case the host name in the request is not trusted. */ public static function createFromRequest(Request $request, $class_loader, $environment, $allow_dumping = TRUE) { // Include our bootstrap file. @@ -222,6 +225,16 @@ public static function createFromRequest(Request $request, $class_loader, $envir $kernel->setSitePath($site_path); Settings::initialize(dirname($core_root), $site_path, $class_loader); + // Initialize our list of trusted HTTP Host headers to protect against + // header attacks. This can be bypassed by setting + // $settings['bypass_trusted_hosts'] = TRUE; + $bypass_trusted_hosts = Settings::get('bypass_trusted_hosts', FALSE); + if (PHP_SAPI !== 'cli' && !$bypass_trusted_hosts) { + if (static::setupTrustedHosts($request) === FALSE) { + throw new BadRequestHttpException(); + } + } + // Redirect the user to the installation script if Drupal has not been // installed yet (i.e., if no $databases array has been defined in the // settings.php file) and we are not already installing. @@ -1312,4 +1325,66 @@ public static function validateHostname(Request $request) { return TRUE; } + /** + * Sets up the lists of trusted HTTP Host headers. + * + * Since the HTTP Host header can be set by the user making the request, it + * is possible to create an attack vectors against a site by overriding this. + * Symfony provides a mechanism for creating a list of trusted Host values. + * + * The default list of trusted hosts is set to + * - localhost + * - locahost.* + * - *.local + * - the value of $_SERVER['SERVER_NAME'], which is set by the system + * administrator. + * + * The default list should be sufficient for installations running a single + * site off of a canonical domain name. Additional host patterns (as + * regular expressions) can be configured throught settings.php for multisite + * installations, sites using ServerAlias without canonical redirection, or + * configurations where the site responds to default requests. For example, + * + * @code + * $settings['trusted_host_patterns'] = array( + * '^example\.com$', + * '^*.example\.com$', + * ); + * @endcode + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request object + * + * @return boolean + * TRUE if the Host header is trusted, FALSE otherwise + * + * @see https://www.drupal.org/node/1992030 + */ + public static function setupTrustedHosts(Request $request) { + $hostPatterns = Settings::get('trusted_host_patterns', array()); + + // Allow an empty Host header + $hostPatterns += array( + '^localhost$', + '^localhost\.*$', + '\.local$', + ); + + $server_name = $request->server->get('SERVER_NAME'); + if (!empty($server_name)) { + $hostPatterns[] = $server_name; + } + + $request->setTrustedHosts($hostPatterns); + + // Get the host, which will validate the current request. + try { + $request->getHost(); + } + catch (\UnexpectedValueException $e) { + return FALSE; + } + + return TRUE; + } } diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php index 4a08788..34d9765 100644 --- a/core/modules/views_ui/src/ViewUI.php +++ b/core/modules/views_ui/src/ViewUI.php @@ -612,7 +612,7 @@ public function renderPreview($display_id, $args = array()) { // Make view links come back to preview. // Also override the current path so we get the pager. - $request = new Request(); + $request = Request::createFromGlobals(); $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'entity.view.preview_form'); $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, \Drupal::service('router.route_provider')->getRouteByName('entity.view.preview_form')); $request->attributes->set('view', $this->storage); @@ -622,6 +622,12 @@ public function renderPreview($display_id, $args = array()) { $raw_parameters->set('display_id', $display_id); $request->attributes->set('_raw_variables', $raw_parameters); + $hostPatterns = $current_request->getTrustedHosts(); + $hostPatterns = array_map(function ($hostPattern) { + return substr($hostPattern, 1, -2); + }, $hostPatterns); + $request->setTrustedHosts($hostPatterns); + foreach ($args as $key => $arg) { $request->attributes->set('arg_' . $key, $arg); } diff --git a/core/tests/Drupal/Tests/Core/DrupalKernel/TrustedHostsTest.php b/core/tests/Drupal/Tests/Core/DrupalKernel/TrustedHostsTest.php new file mode 100644 index 0000000..d59b2f9 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/DrupalKernel/TrustedHostsTest.php @@ -0,0 +1,29 @@ +fail(); + } + +}