diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 0ff2e891479f787479d8bc716b0fbd7391b1776e..d722d6b2db0b34f56ef382f086fc492b8d91a3be 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -201,6 +201,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.
@@ -217,6 +220,15 @@ 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.
+    $hostPatterns = Settings::get('trusted_host_patterns', array());
+    if (PHP_SAPI !== 'cli' && !empty($hostPatterns)) {
+      if (static::setupTrustedHosts($request, $hostPatterns) === FALSE) {
+        throw new BadRequestHttpException('The provided host name is not valid for this server.');
+      }
+    }
+
     // 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.
@@ -1266,4 +1278,46 @@ 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.
+   *
+   * 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.
+   * @param array $hostPatterns
+   *   The array of trusted host patterns.
+   *
+   * @return boolean
+   *   TRUE if the Host header is trusted, FALSE otherwise.
+   *
+   * @see https://www.drupal.org/node/1992030
+   */
+  protected static function setupTrustedHosts(Request $request, $hostPatterns) {
+    $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/system/src/PathBasedBreadcrumbBuilder.php b/core/modules/system/src/PathBasedBreadcrumbBuilder.php
index 05693312e1096626273b82e46f4db48b23e22d2a..6080d6b8f2a8c8cff612821e1f7d7fb7da799744 100644
--- a/core/modules/system/src/PathBasedBreadcrumbBuilder.php
+++ b/core/modules/system/src/PathBasedBreadcrumbBuilder.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system;
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Access\AccessManagerInterface;
 use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
@@ -14,19 +15,17 @@
 use Drupal\Core\Link;
 use Drupal\Core\ParamConverter\ParamNotConvertedException;
 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
+use Drupal\Core\Routing\RequestContext;
 use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\Request;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
-use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
-use Symfony\Component\Routing\RequestContext;
 use Symfony\Component\Routing\Exception\MethodNotAllowedException;
 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
 
 /**
  * Class to define the menu_link breadcrumb builder.
@@ -37,7 +36,7 @@ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
   /**
    * The router request context.
    *
-   * @var \Symfony\Component\Routing\RequestContext
+   * @var \Drupal\Core\Routing\RequestContext
    */
   protected $context;
 
@@ -86,7 +85,7 @@ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
   /**
    * Constructs the PathBasedBreadcrumbBuilder.
    *
-   * @param \Symfony\Component\Routing\RequestContext $context
+   * @param \Drupal\Core\Routing\RequestContext $context
    *   The router request context.
    * @param \Drupal\Core\Access\AccessManagerInterface $access_manager
    *   The menu link access service.
@@ -182,7 +181,7 @@ protected function getRequestForPath($path, array $exclude) {
     }
     // @todo Use the RequestHelper once https://drupal.org/node/2090293 is
     //   fixed.
-    $request = Request::create($this->context->getBaseUrl() . '/' . $path);
+    $request = Request::create($this->context->getCompleteBaseUrl() . '/' . $path);
     // Performance optimization: set a short accept header to reduce overhead in
     // AcceptHeaderMatcher when matching the request.
     $request->headers->set('Accept', 'text/html');
diff --git a/core/modules/system/src/Tests/System/TrustedHostsTest.php b/core/modules/system/src/Tests/System/TrustedHostsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2be2c8b70fe58b5844357e732662920e38694bf6
--- /dev/null
+++ b/core/modules/system/src/Tests/System/TrustedHostsTest.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\System\TrustedHostsTest.
+ */
+
+namespace Drupal\system\Tests\System;
+
+use Drupal\Core\Site\Settings;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests output on the status overview page.
+ *
+ * @group system
+ */
+class TrustedHostsTest extends WebTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $admin_user = $this->drupalCreateUser(array(
+      'administer site configuration',
+    ));
+    $this->drupalLogin($admin_user);
+  }
+
+  /**
+   * Tests that the status page shows an error when the trusted host setting
+   * is missing from settings.php
+   */
+  public function testStatusPageWithoutConfiguration() {
+    $this->drupalGet('admin/reports/status');
+    $this->assertResponse(200, 'The status page is reachable.');
+
+    $this->assertRaw(t('Trusted Host Settings'));
+    $this->assertRaw(t('The trusted_host_patterns setting is not configured in settings.php.'));
+  }
+
+  /**
+   * Tests that the status page shows the trusted patterns from settings.php.
+   */
+  public function testStatusPageWithConfiguration() {
+    $settings['settings']['trusted_host_patterns'] = (object) array(
+      'value' => array('^' . preg_quote(\Drupal::request()->getHost()) . '$'),
+      'required' => TRUE,
+    );
+
+    $this->writeSettings($settings);
+
+    $this->drupalGet('admin/reports/status');
+    $this->assertResponse(200, 'The status page is reachable.');
+
+    $this->assertRaw(t('Trusted Host Settings'));
+    $this->assertRaw(t('The trusted_host_patterns setting is set to allow'));
+  }
+
+}
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 08e7865983fdec7b3a09935e659de3445e3616ce..4a8683eaae8ad41b46eaf245a24f50c1f255f560 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -611,6 +611,28 @@ 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 = Settings::get('trusted_host_patterns');
+    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 <strong>highly recommended</strong> that you configure this. See <a href="@url">Protecting against HTTP HOST Header attacks</a> 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' => join(', ', $trusted_host_patterns))),
+      );
+    }
+  }
+
   return $requirements;
 }
 
diff --git a/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php b/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
index 7daf8c2fa9c24bc1d7b3600ea2aaa56067015677..fb530299c40f10d585592f6adab54c29b790933d 100644
--- a/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
+++ b/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
@@ -58,7 +58,7 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
   /**
    * The mocked route request context.
    *
-   * @var \Symfony\Component\Routing\RequestContext|\PHPUnit_Framework_MockObject_MockObject
+   * @var \Drupal\Core\Routing\RequestContext|\PHPUnit_Framework_MockObject_MockObject
    */
   protected $context;
 
@@ -89,7 +89,7 @@ protected function setUp() {
     $config_factory = $this->getConfigFactoryStub(array('system.site' => array('front' => 'test_frontpage')));
 
     $this->pathProcessor = $this->getMock('\Drupal\Core\PathProcessor\InboundPathProcessorInterface');
-    $this->context = $this->getMock('\Symfony\Component\Routing\RequestContext');
+    $this->context = $this->getMock('\Drupal\Core\Routing\RequestContext');
 
     $this->accessManager = $this->getMock('\Drupal\Core\Access\AccessManagerInterface');
     $this->titleResolver = $this->getMock('\Drupal\Core\Controller\TitleResolverInterface');
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 2f3e417d4252668c241a9c9b0c0333711a4e0902..e8464fa31ecb5b60e361cad57c568ecad5d8eb7c 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -611,8 +611,9 @@ 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();
+      // Also override the current path so we get the pager, and make sure the
+      // Request object gets all of the proper values from $_SERVER.
+      $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);
diff --git a/core/tests/Drupal/Tests/Core/DrupalKernel/DrupalKernelTrustedHostsTest.php b/core/tests/Drupal/Tests/Core/DrupalKernel/DrupalKernelTrustedHostsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3a495118e4ec09739ba13fa378a2250f7eed0449
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/DrupalKernel/DrupalKernelTrustedHostsTest.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\DrupalKernel\DrupalKernelTrustedHostsTest.
+ */
+
+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 DrupalKernelTrustedHostsTest extends UnitTestCase {
+
+  /**
+   * Tests hostname validation with settings.
+   *
+   * @covers ::setupTrustedHosts()
+   *
+   * @dataProvider providerTestTrustedHosts
+   */
+  public function testTrustedHosts($host, $server_name, $message, $expected = FALSE) {
+    $request = new Request();
+
+    $trusted_host_patterns = [
+      '^example\.com$',
+      '^.+\.example\.com$',
+      '^example\.org',
+      '^.+\.example\.org',
+    ];
+
+    if (!empty($host)) {
+      $request->headers->set('HOST', $host);
+    }
+
+    $request->server->set('SERVER_NAME', $server_name);
+
+    $method = new \ReflectionMethod('Drupal\Core\DrupalKernel', 'setupTrustedHosts');
+    $method->setAccessible(TRUE);
+    $valid_host = $method->invoke(null, $request, $trusted_host_patterns);
+
+    $this->assertSame($expected, $valid_host, $message);
+
+    // Reset the trusted hosts because it is statically stored on the request.
+    $method->invoke(null, $request, []);
+  }
+
+  /**
+   * Provides test data for testTrustedHosts().
+   */
+  public function providerTestTrustedHosts() {
+    $data = [];
+
+    // Tests canonical URL.
+    $data[] = ['www.example.com', 'www.example.com', 'canonical URL is trusted', TRUE];
+
+    // Tests missing hostname for HTTP/1.0 compatability where the Host
+    // header is optional.
+    $data[] = [NULL, 'www.example.com', 'empty Host is valid', TRUE];
+
+    // Tests the additional paterns from the settings.
+    $data[] = ['example.com', 'www.example.com', 'host from settings is trusted', TRUE];
+    $data[] = ['subdomain.example.com', 'www.example.com', 'host from settings is trusted', TRUE];
+    $data[] = ['www.example.org', 'www.example.com', 'host from settings is trusted', TRUE];
+    $data[] = ['example.org', 'www.example.com', 'host from settings is trusted', TRUE];
+
+    // Tests mismatch.
+    $data[] = ['www.blackhat.com', 'www.example.com', 'unspecified host is untrusted', FALSE];
+
+    return $data;
+  }
+
+}
diff --git a/index.php b/index.php
index 55fc9474985adafd4c8946221d7fdc903e8862c8..867f0e09215ae4f7a0bc0256e28ea89cc56850c4 100644
--- a/index.php
+++ b/index.php
@@ -27,7 +27,7 @@
   $kernel->terminate($request, $response);
 }
 catch (HttpExceptionInterface $e) {
-  $response = new Response('', $e->getStatusCode());
+  $response = new Response($e->getMessage(), $e->getStatusCode());
   $response->prepare($request)->send();
 }
 catch (Exception $e) {
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index 76d26fcfdf3c5ef11b65b20f518261e885139d1d..7cc10be7260ccade7699c9d7831d6328f6b770d4 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -607,3 +607,40 @@
 # if (file_exists(__DIR__ . '/settings.local.php')) {
 #   include __DIR__ . '/settings.local.php';
 # }
+
+/**
+ * Trusted host configuration.
+ *
+ * Drupal core can use the Symfony trusted host mechanism to prevent HTTP Host
+ * header spoofing.
+ *
+ * To enable the trusted host mechanism, you enable your allowable hosts
+ * in $settings['trusted_host_patterns']. This should be an array of regular
+ * expression patterns, without delimiters, representing the hosts you would
+ * like to allow.
+ *
+ * For example:
+ * @code
+ * $settings['trusted_host_patterns'] = array(
+ *   '^www\.example\.com$',
+ * );
+ * @endcode
+ * will allow the site to only run from www.example.com.
+ *
+ * If you are running multisite, or if you are running your site from
+ * different domain names (eg, you don't redirect http://www.example.com to
+ * http://example.com), you should specify all of the host patterns that are
+ * allowed by your site.
+ *
+ * For example:
+ * @code
+ * $settings['trusted_host_patterns'] = array(
+ *   '^example\.com$',
+ *   '^.+\.example\.com$',
+ *   '^example\.org',
+ *   '^.+\.example\.org',
+ * );
+ * @endcode
+ * will allow the site to run off of all variants of example.com and
+ * example.org, with all subdomains included.
+ */
diff --git a/sites/example.settings.local.php b/sites/example.settings.local.php
index 7859fe5021951e9a393204ae347e5a690f440f9b..3d5857a306b356158793eb72e131e983e5ad3aef 100644
--- a/sites/example.settings.local.php
+++ b/sites/example.settings.local.php
@@ -55,3 +55,15 @@
  * using these parameters in a request to rebuild.php.
  */
 $settings['rebuild_access'] = TRUE;
+
+/**
+ * Trust localhost.
+ *
+ * This will configure several common hostnames used for local development to
+ * be trusted hosts.
+ */
+$settings['trusted_host_patterns'] = array(
+  '^localhost$',
+  '^localhost\.*',
+  '\.local$',
+);