From 6b8a1e13c6b02359c79ff3c07e0f5b8921c72498 Mon Sep 17 00:00:00 2001 From: Oliver Hader <oliver@typo3.org> Date: Tue, 16 Mar 2021 10:16:03 +0100 Subject: [PATCH] [SECURITY] Avoid storing plain session identifier in $USER->uc `AbstractUserAuthentication::$uc['moduleSessionID']` still stored plain session identifier, which has been replaced by corresponding HMAC. Resolves: #93359 Releases: master, 11.1, 10.4, 9.5 Change-Id: I920b8d3b364c249d2ec3a6deb42e141e5a1b8ff7 Security-Bulletin: TYPO3-CORE-SA-2021-006 Security-References: CVE-2021-21339 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/68439 Tested-by: Oliver Hader <oliver.hader@typo3.org> Reviewed-by: Oliver Hader <oliver.hader@typo3.org> --- .../AbstractUserAuthentication.php | 20 ++++- .../AbstractUserAuthenticationTest.php | 84 +++++++++++++++++++ .../Fixtures/AnyUserAuthentication.php | 40 +++++++++ 3 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 typo3/sysext/core/Tests/Functional/Authentication/AbstractUserAuthenticationTest.php create mode 100644 typo3/sysext/core/Tests/Functional/Authentication/Fixtures/AnyUserAuthentication.php diff --git a/typo3/sysext/core/Classes/Authentication/AbstractUserAuthentication.php b/typo3/sysext/core/Classes/Authentication/AbstractUserAuthentication.php index 5cb97907446f..f531817f82cb 100644 --- a/typo3/sysext/core/Classes/Authentication/AbstractUserAuthentication.php +++ b/typo3/sysext/core/Classes/Authentication/AbstractUserAuthentication.php @@ -1019,8 +1019,12 @@ abstract class AbstractUserAuthentication implements LoggerAwareInterface */ public function pushModuleData($module, $data, $noSave = 0) { + $sessionHash = GeneralUtility::hmac( + $this->userSession->getIdentifier(), + 'core-session-hash' + ); $this->uc['moduleData'][$module] = $data; - $this->uc['moduleSessionID'][$module] = $this->userSession->getIdentifier(); + $this->uc['moduleSessionID'][$module] = $sessionHash; if (!$noSave) { $this->writeUC(); } @@ -1035,8 +1039,18 @@ abstract class AbstractUserAuthentication implements LoggerAwareInterface */ public function getModuleData($module, $type = '') { - if ($type !== 'ses' || (isset($this->uc['moduleSessionID'][$module]) && $this->uc['moduleSessionID'][$module] == $this->userSession->getIdentifier())) { - return $this->uc['moduleData'][$module]; + $sessionHash = GeneralUtility::hmac( + $this->userSession->getIdentifier(), + 'core-session-hash' + ); + $sessionData = $this->uc['moduleData'][$module] ?? null; + $moduleSessionIdHash = $this->uc['moduleSessionID'][$module] ?? null; + if ($type !== 'ses' + || $sessionData !== null && $moduleSessionIdHash === $sessionHash + // @todo Fallback for non-hashed values in `moduleSessionID`, remove for TYPO3 v11.5 LTS + || $sessionData !== null && $moduleSessionIdHash === $this->userSession->getIdentifier() + ) { + return $sessionData; } return null; } diff --git a/typo3/sysext/core/Tests/Functional/Authentication/AbstractUserAuthenticationTest.php b/typo3/sysext/core/Tests/Functional/Authentication/AbstractUserAuthenticationTest.php new file mode 100644 index 000000000000..a3b193581acb --- /dev/null +++ b/typo3/sysext/core/Tests/Functional/Authentication/AbstractUserAuthenticationTest.php @@ -0,0 +1,84 @@ +<?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\Tests\Functional\Authentication; + +use TYPO3\CMS\Core\Session\UserSession; +use TYPO3\CMS\Core\Tests\Functional\Authentication\Fixtures\AnyUserAuthentication; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; + +class AbstractUserAuthenticationTest extends FunctionalTestCase +{ + /** + * @var string + */ + private $sessionId; + + /** + * @var AnyUserAuthentication + */ + private $subject; + + /** + * @var UserSession + */ + private $userSession; + + protected function setUp(): void + { + parent::setUp(); + $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = '12345'; + $this->sessionId = bin2hex(random_bytes(20)); + $this->userSession = UserSession::createNonFixated($this->sessionId); + $this->subject = new AnyUserAuthentication($this->userSession); + } + + protected function tearDown(): void + { + unset($this->sessionId, $this->userSession, $this->subject); + unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']); + parent::tearDown(); + } + + /** + * @test + */ + public function pushModuleDataDoesNotRevealPlainSessionId(): void + { + $this->subject->pushModuleData(self::class, true); + self::assertNotContains($this->sessionId, $this->subject->uc['moduleSessionID']); + } + + /** + * @test + */ + public function getModuleDataResolvesHashedSessionId(): void + { + $this->subject->pushModuleData(self::class, true); + self::assertTrue($this->subject->getModuleData(self::class)); + } + + /** + * @test + */ + public function getModuleDataFallsBackToPlainSessionId(): void + { + $this->subject->uc['moduleData'][self::class] = true; + $this->subject->uc['moduleSessionID'][self::class] = $this->sessionId; + self::assertTrue($this->subject->getModuleData(self::class)); + } +} diff --git a/typo3/sysext/core/Tests/Functional/Authentication/Fixtures/AnyUserAuthentication.php b/typo3/sysext/core/Tests/Functional/Authentication/Fixtures/AnyUserAuthentication.php new file mode 100644 index 000000000000..321cb614d013 --- /dev/null +++ b/typo3/sysext/core/Tests/Functional/Authentication/Fixtures/AnyUserAuthentication.php @@ -0,0 +1,40 @@ +<?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\Tests\Functional\Authentication\Fixtures; + +use TYPO3\CMS\Core\Authentication\AbstractUserAuthentication; +use TYPO3\CMS\Core\Session\UserSession; + +class AnyUserAuthentication extends AbstractUserAuthentication +{ + /** + * @var array + */ + public $uc = []; + + /** + * @var string + */ + public $loginType = 'ANY'; + + public function __construct(UserSession $userSession) + { + parent::__construct(); + $this->userSession = $userSession; + } +} -- GitLab