diff --git a/core/authorize.php b/core/authorize.php
index 22bede6..86a1ad5 100644
--- a/core/authorize.php
+++ b/core/authorize.php
@@ -54,9 +54,16 @@ function authorize_access_allowed() {
   return Settings::get('allow_authorize_operations', TRUE) && \Drupal::currentUser()->hasPermission('administer software updates');
 }
 
-$request = Request::createFromGlobals();
-$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
-$kernel->prepareLegacyRequest($request);
+try {
+  $request = Request::createFromGlobals();
+  $kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
+  $kernel->prepareLegacyRequest($request);
+}
+catch (HttpException $e) {
+  $response = new Response('', $e->getStatusCode());
+  $response->prepare($request)->send();
+  exit;
+}
 
 // We have to enable the user and system modules, even to check access and
 // display errors via the maintenance theme.
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 600fd21..f55b0d9 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -29,6 +29,7 @@
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
 use Symfony\Component\HttpKernel\TerminableInterface;
 use Composer\Autoload\ClassLoader;
 
@@ -293,12 +294,18 @@ public function __construct($environment, $class_loader, $allow_dumping = TRUE)
    * @return string
    *   The path of the matching directory.
    *
+   * @throws BadRequestHttpException
+   *
    * @see \Drupal\Core\DrupalKernelInterface::getSitePath()
    * @see \Drupal\Core\DrupalKernelInterface::setSitePath()
    * @see default.settings.php
    * @see example.sites.php
    */
   public static function findSitePath(Request $request, $require_settings = TRUE) {
+    if (static::validateHostname($request) !== TRUE) {
+      throw new BadRequestHttpException();
+    }
+
     // Check for a simpletest override.
     if ($test_prefix = drupal_valid_test_ua()) {
       return 'sites/simpletest/' . substr($test_prefix, 10);
@@ -314,7 +321,7 @@ public static function findSitePath(Request $request, $require_settings = TRUE)
     if (!$script_name) {
       $script_name = $request->server->get('SCRIPT_FILENAME');
     }
-    $http_host = $request->server->get('HTTP_HOST');
+    $http_host = $request->getHost();
 
     $sites = array();
     include DRUPAL_ROOT . '/sites/sites.php';
@@ -809,8 +816,7 @@ protected function initializeRequestGlobals(Request $request) {
     }
     else {
       // Create base URL.
-      $http_protocol = $request->isSecure() ? 'https' : 'http';
-      $base_root = $http_protocol . '://' . $request->server->get('HTTP_HOST');
+      $base_root = $request->getSchemeAndHttpHost();
 
       $base_url = $base_root;
 
@@ -892,16 +898,13 @@ protected function initializeCookieGlobals(Request $request) {
       // Replace "core" out of session_name so core scripts redirect properly,
       // specifically install.php.
       $session_name = preg_replace('/\/core$/', '', $session_name);
-      // HTTP_HOST can be modified by a visitor, but has been sanitized already
-      // in DrupalKernel::bootEnvironment().
-      if ($cookie_domain = $request->server->get('HTTP_HOST')) {
-        // Strip leading periods, www., and port numbers from cookie domain.
+      if ($cookie_domain = $request->getHost()) {
+        // Strip leading periods and www. from cookie domain.
         $cookie_domain = ltrim($cookie_domain, '.');
         if (strpos($cookie_domain, 'www.') === 0) {
           $cookie_domain = substr($cookie_domain, 4);
         }
-        $cookie_domain = explode(':', $cookie_domain);
-        $cookie_domain = '.' . $cookie_domain[0];
+        $cookie_domain = '.' . $cookie_domain;
       }
     }
     // Per RFC 2109, cookie domains must contain at least one dot other than the
@@ -1249,4 +1252,50 @@ protected function classLoaderAddMultiplePsr4(array $namespaces = array()) {
     }
   }
 
+  /**
+   * Validates a hostname length.
+   *
+   * @param string $host
+   *   A hostname.
+   *
+   * @return bool
+   *   TRUE if the length is appropriate, or FALSE otherwise.
+   */
+  protected static function validateHostnameLength($host) {
+    // Limit the length of the host name to 1000 bytes to prevent DoS attacks
+    // with long host names.
+    return strlen($host) <= 1000
+    // Limit the number of subdomains and port separators to prevent DoS attacks
+    // in findSitePath().
+    && substr_count($host, '.') <= 100
+    && substr_count($host, ':') <= 100;
+  }
+
+  /**
+   * Validates the hostname supplied from the HTTP request.
+   *
+   * @param Request $request
+   *   The request object
+   *
+   * @return bool
+   *   TRUE if the hostmame is valid, or FALSE otherwise.
+   *
+   * @todo Adjust per resolution to https://github.com/symfony/symfony/issues/12349
+   */
+  public static function validateHostname(Request $request) {
+    // $request->getHost() can also throw an UnexpectedValueException if it
+    // detects a bad hostname, but it does not validate the length.
+    try {
+      $http_host = $request->getHost();
+      if (static::validateHostnameLength($http_host) !== TRUE) {
+        throw new \UnexpectedValueException('Bad hostname');
+      }
+    }
+    catch (\UnexpectedValueException $e) {
+      return FALSE;
+    }
+
+    return TRUE;
+  }
+
 }
diff --git a/core/rebuild.php b/core/rebuild.php
index c915aff..bbe0f18 100644
--- a/core/rebuild.php
+++ b/core/rebuild.php
@@ -14,6 +14,7 @@
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Site\Settings;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 
 // Change the directory to the Drupal root.
 chdir('..');
@@ -25,7 +26,15 @@
 // Manually resemble early bootstrap of DrupalKernel::boot().
 require_once __DIR__ . '/includes/bootstrap.inc';
 DrupalKernel::bootEnvironment();
-Settings::initialize(DrupalKernel::findSitePath($request), $autoloader);
+
+try {
+  Settings::initialize(DrupalKernel::findSitePath($request), $autoloader);
+}
+catch (HttpException $e) {
+  $response = new Response('', $e->getStatusCode());
+  $response->prepare($request)->send();
+  exit;
+}
 
 if (Settings::get('rebuild_access', FALSE) ||
   ($request->get('token') && $request->get('timestamp') &&
diff --git a/core/tests/Drupal/Tests/Core/DrupalKernel/ValidateHostnameTest.php b/core/tests/Drupal/Tests/Core/DrupalKernel/ValidateHostnameTest.php
new file mode 100644
index 0000000..042909b
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/DrupalKernel/ValidateHostnameTest.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\DrupalKernel\ValidateHostnameTest.
+ */
+
+namespace Drupal\Tests\Core\DrupalKernel;
+
+use Drupal\Core\DrupalKernel;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * @coversDefaultClass \Drupal\Core\DrupalKernel
+ * @group DrupalKernel
+ */
+class ValidateHostnameTest extends UnitTestCase {
+
+  /**
+   * Tests hostname validation.
+   *
+   * @covers ::validateHostname()
+   */
+  public function testValidateHostame() {
+    // Save off the server array.
+    $server = $_SERVER;
+
+    // Verifies that DrupalKernel::validateHostname() prevents invalid
+    // characters.
+    $this->assertFalse($this->validHttpHost('security/.drupal.org:80'), 'HTTP_HOST with / is invalid');
+    $this->assertFalse($this->validHttpHost('security\\.drupal.org:80'), 'HTTP_HOST with \\ is invalid');
+    $this->assertFalse($this->validHttpHost('security<.drupal.org:80'), 'HTTP_HOST with &lt; is invalid');
+    $this->assertFalse($this->validHttpHost('security..drupal.org:80'), 'HTTP_HOST with .. is invalid');
+    // Verifies that host names are shorter than 1000 characters.
+    $this->assertFalse($this->validHttpHost(str_repeat('x', 1001)), 'HTTP_HOST with more than 1000 characters is invalid.');
+    $this->assertFalse($this->validHttpHost(str_repeat('.', 101)), 'HTTP_HOST with more than 100 subdomains is invalid.');
+    $this->assertFalse($this->validHttpHost(str_repeat(':', 101)), 'HTTP_HOST with more than 100 portseparators is invalid.');
+
+    // Restore the global server array, and make sure normal requests still
+    // work.
+    $_SERVER = $server;
+    $request = Request::createFromGlobals();
+    $ok = DrupalKernel::validateHostname($request);
+    $this->assertTrue($ok, 'Original HTTP_HOST is valid');
+  }
+
+  /**
+   * Validates a spoofed HTTP_HOST.
+   *
+   * @param $hostname
+   *   The hostname to use for the HTTP_HOST.
+   *
+   * @return bool
+   *   TRUE if the spoofed hostname is valid, FALSE otherwise.
+   */
+  protected function validHttpHost($hostname) {
+    $_SERVER['HTTP_HOST'] = $hostname;
+    $request = Request::createFromGlobals();
+    return DrupalKernel::validateHostname($request);
+  }
+
+}
diff --git a/index.php b/index.php
index 406d3dc..1587673 100644
--- a/index.php
+++ b/index.php
@@ -10,7 +10,9 @@
 
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 
 $autoloader = require_once __DIR__ . '/core/vendor/autoload.php';
 
@@ -24,6 +26,10 @@
       ->prepare($request)->send();
   $kernel->terminate($request, $response);
 }
+catch (HttpException $e) {
+  $response = new Response('', $e->getStatusCode());
+  $response->prepare($request)->send();
+}
 catch (Exception $e) {
   $message = 'If you have just changed code (for example deployed a new module or moved an existing one) read <a href="http://drupal.org/documentation/rebuild">http://drupal.org/documentation/rebuild</a>';
   if (Settings::get('rebuild_access', FALSE)) {
