Permalink
Show file tree
Hide file tree
3 changes: 1 addition & 2 deletions
3
typo3/sysext/core/Tests/Acceptance/Application/InstallTool/UpgradeCest.php
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[SECURITY] Verify HTTP_HOST via FE/BE middleware
Avoid a dependency cycle between HTTP_HOST generation and verification. As $GLOBALS['TYPO3_REQUEST'] is not available during ServerRequestFactory::fromGlobals(), HTTP_HOST verification can not be performed at that point. It is therefore delayed into a context aware middleware instead of being skipped because of missing $GLOBALS. Positive advantage of moving the verification into frontend and backend middlewares, is that context checks to exclude CLI/installtool can be dropped. As a side effect this also fixes the frontend to installtool redirect if TYPO3 is not yet configured and running with an invalid SERVER_NAME, as ServerRequestFactory::fromGlobals() doesn't fail. Releases: master Resolves: #95395 Change-Id: Idd3a3449a878cd625dad0d04892d9f0e710ca1a9 Security-Bulletin: TYPO3-CORE-SA-2021-015 Security-References: CVE-2021-41114 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/71438 Tested-by: Oliver Hader <oliver.hader@typo3.org> Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
- Loading branch information
Showing
17 changed files
with
531 additions
and
387 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
typo3/sysext/core/Classes/Middleware/VerifyHostHeader.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| /* | ||
| * This file is part of the TYPO3 CMS project. | ||
| * | ||
| * It is free software; you can redistribute it and/or modify it under | ||
| * the terms of the GNU General Public License, either version 2 | ||
| * of the License, or any later version. | ||
| * | ||
| * For the full copyright and license information, please read the | ||
| * LICENSE.txt file that was distributed with this source code. | ||
| * | ||
| * The TYPO3 project - inspiring people to share! | ||
| */ | ||
|
|
||
| namespace TYPO3\CMS\Core\Middleware; | ||
|
|
||
| use Psr\Http\Message\ResponseInterface; | ||
| use Psr\Http\Message\ServerRequestInterface; | ||
| use Psr\Http\Server\MiddlewareInterface; | ||
| use Psr\Http\Server\RequestHandlerInterface; | ||
|
|
||
| /** | ||
| * Checks if the provided host header value matches the trusted hosts pattern. | ||
| * | ||
| * @internal | ||
| */ | ||
| class VerifyHostHeader implements MiddlewareInterface | ||
| { | ||
| public const ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL = '.*'; | ||
| public const ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME = 'SERVER_NAME'; | ||
|
|
||
| protected string $trustedHostsPattern; | ||
|
|
||
| public function __construct(string $trustedHostsPattern) | ||
| { | ||
| $this->trustedHostsPattern = $trustedHostsPattern; | ||
| } | ||
|
|
||
| public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface | ||
| { | ||
| $serverParams = $request->getServerParams(); | ||
| $httpHost = $serverParams['HTTP_HOST'] ?? ''; | ||
| if (!$this->isAllowedHostHeaderValue($httpHost, $serverParams)) { | ||
| throw new \UnexpectedValueException( | ||
| 'The current host header value does not match the configured trusted hosts pattern!' | ||
| . ' Check the pattern defined in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'trustedHostsPattern\']' | ||
| . ' and adapt it, if you want to allow the current host header \'' . $httpHost . '\' for your installation.', | ||
| 1396795884 | ||
| ); | ||
| } | ||
|
|
||
| return $handler->handle($request); | ||
| } | ||
|
|
||
| /** | ||
| * Checks if the provided host header value matches the trusted hosts pattern. | ||
| * | ||
| * @param string $hostHeaderValue HTTP_HOST header value as sent during the request (may include port) | ||
| * @return bool | ||
| */ | ||
| public function isAllowedHostHeaderValue(string $hostHeaderValue, array $serverParams): bool | ||
| { | ||
| // Deny the value if trusted host patterns is empty, which means configuration is invalid. | ||
| if ($this->trustedHostsPattern === '') { | ||
| return false; | ||
| } | ||
|
|
||
| if ($this->trustedHostsPattern === self::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL) { | ||
| return true; | ||
| } | ||
|
|
||
| return $this->hostHeaderValueMatchesTrustedHostsPattern($hostHeaderValue, $serverParams); | ||
| } | ||
|
|
||
| /** | ||
| * Checks if the provided host header value matches the trusted hosts pattern without any preprocessing. | ||
| */ | ||
| protected function hostHeaderValueMatchesTrustedHostsPattern(string $hostHeaderValue, array $serverParams): bool | ||
| { | ||
| if ($this->trustedHostsPattern === self::ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME) { | ||
| $host = strtolower($hostHeaderValue); | ||
| // Default port to be verified if HTTP_HOST does not contain explicit port information. | ||
| // Deriving from raw/local webserver HTTPS information (not taking possible proxy configurations into account) | ||
| // as we compare against the raw/local server information (SERVER_PORT). | ||
| $port = self::webserverUsesHttps($serverParams) ? '443' : '80'; | ||
|
|
||
| $parsedHostValue = parse_url('http://' . $host); | ||
| if (isset($parsedHostValue['port'])) { | ||
| $host = $parsedHostValue['host']; | ||
| $port = (string)$parsedHostValue['port']; | ||
| } | ||
|
|
||
| // Allow values that equal the server name | ||
| // Note that this is only secure if name base virtual host are configured correctly in the webserver | ||
| $hostMatch = $host === strtolower($serverParams['SERVER_NAME']) && $port === $serverParams['SERVER_PORT']; | ||
| } else { | ||
| // In case name based virtual hosts are not possible, we allow setting a trusted host pattern | ||
| // See https://typo3.org/teams/security/security-bulletins/typo3-core/typo3-core-sa-2014-001/ for further details | ||
| $hostMatch = (bool)preg_match('/^' . $this->trustedHostsPattern . '$/i', $hostHeaderValue); | ||
| } | ||
|
|
||
| return $hostMatch; | ||
| } | ||
|
|
||
| /** | ||
| * Determine if the webserver uses HTTPS. | ||
| * | ||
| * HEADS UP: This does not check if the client performed a | ||
| * HTTPS request, as possible proxies are not taken into | ||
| * account. It provides raw information about the current | ||
| * webservers configuration only. | ||
| */ | ||
| protected function webserverUsesHttps(array $serverParams): bool | ||
| { | ||
| if (!empty($serverParams['SSL_SESSION_ID'])) { | ||
| return true; | ||
| } | ||
|
|
||
| // https://secure.php.net/manual/en/reserved.variables.server.php | ||
| // "Set to a non-empty value if the script was queried through the HTTPS protocol." | ||
| return !empty($serverParams['HTTPS']) && strtolower($serverParams['HTTPS']) !== 'off'; | ||
| } | ||
| } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
...95395-GeneralUtilityIsAllowedHostHeaderValueAndTrustedHostsPatternConstants.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| .. include:: ../../Includes.txt | ||
|
|
||
| ==================================================================================================== | ||
| Deprecation: #95395 - GeneralUtility::isAllowedHostHeaderValue() and TRUSTED_HOSTS_PATTERN constants | ||
| ==================================================================================================== | ||
|
|
||
| See :issue:`95395` | ||
|
|
||
| Description | ||
| =========== | ||
|
|
||
| The PHP method | ||
| :php:`TYPO3\CMS\Core\Utility\GeneralUtility::isAllowedHostHeaderValue()` | ||
| and the PHP constants | ||
| :php:`TYPO3\CMS\Core\Utility\GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL` | ||
| and | ||
| :php:`TYPO3\CMS\Core\Utility\GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME` | ||
| have been deprecated. | ||
|
|
||
|
|
||
| Impact | ||
| ====== | ||
|
|
||
| A deprecation will be logged in TYPO3 v11 if | ||
| :php:`TYPO3\CMS\Core\Utility\GeneralUtility::isAllowedHostHeaderValue()` is | ||
| used. It is unlikely for extensions to have used this as the host header | ||
| is checked for every frontend and backend request anyway. | ||
|
|
||
| Usage of the constants will cause a PHP error "Undefined class constant" in | ||
| TYPO3 v12, the method | ||
| :php:`TYPO3\CMS\Core\Utility\GeneralUtility::isAllowedHostHeaderValue()` will be | ||
| dropped without replacement. | ||
|
|
||
|
|
||
| Affected Installations | ||
| ====================== | ||
|
|
||
| Installations using the constants instead of static strings or | ||
| call the method explictily – which is unlikely. | ||
|
|
||
|
|
||
| Migration | ||
| ========= | ||
|
|
||
| Use :php:`'.*'` instead of | ||
| :php:`TYPO3\CMS\Core\Utility\GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL` | ||
| and :php:`'SERVER_NAME'` instead of | ||
| :php:`TYPO3\CMS\Core\Utility\GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME`. | ||
|
|
||
| Don't use :php:`TYPO3\CMS\Core\Utility\GeneralUtility::isAllowedHostHeaderValue()`. | ||
|
|
||
|
|
||
| .. index:: PHP-API, FullyScanned, ext:core |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.