Skip to content

Commit

Permalink
[SECURITY] Avoid storing plain session identifier in $USER->uc
Browse files Browse the repository at this point in the history
`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/+/68431
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
  • Loading branch information
ohader committed Mar 16, 2021
1 parent ba66465 commit 71914e5
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 3 deletions.
Expand Up @@ -1019,8 +1019,12 @@ public function unpack_uc($theUC = '')
*/
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();
}
Expand All @@ -1035,8 +1039,18 @@ public function pushModuleData($module, $data, $noSave = 0)
*/
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;
}
Expand Down
@@ -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));
}
}
@@ -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;
}
}

0 comments on commit 71914e5

Please sign in to comment.