‪TYPO3CMS  ‪main
VerifyHostHeader.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Http\Message\ResponseInterface;
21 use Psr\Http\Message\ServerRequestInterface;
22 use Psr\Http\Server\MiddlewareInterface;
23 use Psr\Http\Server\RequestHandlerInterface;
24 
30 class ‪VerifyHostHeader implements MiddlewareInterface
31 {
33  public const ‪ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME = 'SERVER_NAME';
34 
35  protected string ‪$trustedHostsPattern;
36 
37  public function ‪__construct(string ‪$trustedHostsPattern)
38  {
39  $this->trustedHostsPattern = ‪$trustedHostsPattern;
40  }
41 
42  public function ‪process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
43  {
44  $serverParams = $request->getServerParams();
45  $httpHost = $serverParams['HTTP_HOST'] ?? '';
46  if (!$this->‪isAllowedHostHeaderValue($httpHost, $serverParams)) {
47  throw new \UnexpectedValueException(
48  'The current host header value does not match the configured trusted hosts pattern!'
49  . ' Check the pattern defined in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'trustedHostsPattern\']'
50  . ' and adapt it, if you want to allow the current host header \'' . $httpHost . '\' for your installation.',
51  1396795884
52  );
53  }
54 
55  return $handler->handle($request);
56  }
57 
63  public function isAllowedHostHeaderValue(string $hostHeaderValue, array $serverParams): bool
64  {
65  // Deny the value if trusted host patterns is empty, which means configuration is invalid.
66  if ($this->trustedHostsPattern === '') {
67  return false;
68  }
69 
70  if ($this->trustedHostsPattern === self::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL) {
71  return true;
72  }
73 
74  return $this->hostHeaderValueMatchesTrustedHostsPattern($hostHeaderValue, $serverParams);
75  }
76 
80  protected function hostHeaderValueMatchesTrustedHostsPattern(string $hostHeaderValue, array $serverParams): bool
81  {
82  if ($this->trustedHostsPattern === self::ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME) {
83  $host = strtolower($hostHeaderValue);
84  // Default port to be verified if HTTP_HOST does not contain explicit port information.
85  // Deriving from raw/local webserver HTTPS information (not taking possible proxy configurations into account)
86  // as we compare against the raw/local server information (SERVER_PORT).
87  $port = self::webserverUsesHttps($serverParams) ? '443' : '80';
88 
89  $parsedHostValue = parse_url('http://' . $host);
90  ‪if (isset($parsedHostValue['port'])) {
91  $host = $parsedHostValue['host'];
92  $port = (string)$parsedHostValue['port'];
93  }
94 
95  // Allow values that equal the server name
96  // Note that this is only secure if name base virtual host are configured correctly in the webserver
97  $hostMatch = $host === strtolower($serverParams['SERVER_NAME']) && $port === $serverParams['SERVER_PORT'];
98  } else {
99  // In case name based virtual hosts are not possible, we allow setting a trusted host pattern
100  // See https://typo3.org/teams/security/security-bulletins/typo3-core/typo3-core-sa-2014-001/ for further details
101  $hostMatch = (bool)preg_match('/^' . $this->trustedHostsPattern . '$/i', $hostHeaderValue);
102  }
103 
104  return $hostMatch;
105  }
106 
115  protected function ‪webserverUsesHttps(array $serverParams): bool
116  {
117  if (!empty($serverParams['SSL_SESSION_ID'])) {
118  return true;
119  }
120 
121  // https://secure.php.net/manual/en/reserved.variables.server.php
122  // "Set to a non-empty value if the script was queried through the HTTPS protocol."
123  return !empty($serverParams['HTTPS']) && strtolower($serverParams['HTTPS']) !== 'off';
124  }
125 }
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\isAllowedHostHeaderValue
‪isAllowedHostHeaderValue(string $hostHeaderValue, array $serverParams)
Definition: VerifyHostHeader.php:63
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\process
‪process(ServerRequestInterface $request, RequestHandlerInterface $handler)
Definition: VerifyHostHeader.php:42
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\webserverUsesHttps
‪webserverUsesHttps(array $serverParams)
Definition: VerifyHostHeader.php:115
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\__construct
‪__construct(string $trustedHostsPattern)
Definition: VerifyHostHeader.php:37
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL
‪const ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL
Definition: VerifyHostHeader.php:32
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME
‪const ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME
Definition: VerifyHostHeader.php:33
‪TYPO3\CMS\Core\Middleware
Definition: AbstractContentSecurityPolicyReporter.php:18
‪if
‪if(PHP_SAPI !=='cli')
Definition: checkNamespaceIntegrity.php:27
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader
Definition: VerifyHostHeader.php:31
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\$trustedHostsPattern
‪string $trustedHostsPattern
Definition: VerifyHostHeader.php:35