Skip to content

Commit

Permalink
[SECURITY] Destroy user sessions on password change
Browse files Browse the repository at this point in the history
The password reset process for TYPO3 backend and
frontend users does not destroy possible existing
user sessions after the password has been changed.

With this patch, all existing user sessions are
destroyed when the password is changed in the
password reset process.

Resolves: #98462
Releases: main, 11.5, 10.4
Change-Id: I6744bfcf7cae56b4e525f2e0f9a44d06cf14396c
Security-Bulletin: TYPO3-CORE-SA-2022-014
Security-References: CVE-2022-23502
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/77091
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
  • Loading branch information
derhansen authored and ohader committed Dec 13, 2022
1 parent 640a6f6 commit 4a41c71
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 0 deletions.
13 changes: 13 additions & 0 deletions typo3/sysext/backend/Classes/Authentication/PasswordReset.php
Expand Up @@ -39,6 +39,7 @@
use TYPO3\CMS\Core\Http\NormalizedParams;
use TYPO3\CMS\Core\Mail\FluidEmail;
use TYPO3\CMS\Core\Mail\Mailer;
use TYPO3\CMS\Core\Session\SessionManager;
use TYPO3\CMS\Core\SysLog\Action\Login as SystemLogLoginAction;
use TYPO3\CMS\Core\SysLog\Error as SystemLogErrorClassification;
use TYPO3\CMS\Core\SysLog\Type as SystemLogType;
Expand Down Expand Up @@ -348,6 +349,8 @@ public function resetPassword(ServerRequestInterface $request, Context $context)
->getConnectionForTable('be_users')
->update('be_users', ['password_reset_token' => '', 'password' => $this->getHasher()->getHashedPassword($newPassword)], ['uid' => $userId]);

$this->invalidateUserSessions($userId);

$this->logger->info('Password reset successful for user {user_id)', ['user_id' => $userId]);
$this->log(
'Password reset successful for user %s',
Expand Down Expand Up @@ -498,4 +501,14 @@ protected function getNumberOfInitiatedResetsForEmail(\DateTimeInterface $since,
->executeQuery()
->fetchOne();
}

/**
* Invalidate all backend user sessions by given user id
*/
protected function invalidateUserSessions(int $userId): void
{
$sessionManager = GeneralUtility::makeInstance(SessionManager::class);
$sessionBackend = $sessionManager->getSessionBackend('BE');
$sessionManager->invalidateAllSessionsByUserId($sessionBackend, $userId);
}
}
Expand Up @@ -24,6 +24,7 @@
use TYPO3\CMS\Core\Crypto\PasswordHashing\InvalidPasswordHashException;
use TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory;
use TYPO3\CMS\Core\Messaging\AbstractMessage;
use TYPO3\CMS\Core\Session\SessionManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Error\Error;
use TYPO3\CMS\Extbase\Error\Result;
Expand Down Expand Up @@ -227,7 +228,9 @@ public function changePasswordAction(string $newPass, string $hash)
return $hashedPassword;
}

$user = $this->userRepository->findOneByForgotPasswordHash(GeneralUtility::hmac($hash));
$this->userRepository->updatePasswordAndInvalidateHash(GeneralUtility::hmac($hash), $hashedPassword);
$this->invalidateUserSessions($user['uid']);

$this->addFlashMessage($this->getTranslation('change_password_done_message'));

Expand Down Expand Up @@ -331,4 +334,14 @@ protected function exposeNoneExistentUser(?string $email): bool
true
);
}

/**
* Invalidate all frontend user sessions by given user id
*/
protected function invalidateUserSessions(int $userId): void
{
$sessionManager = GeneralUtility::makeInstance(SessionManager::class);
$sessionBackend = $sessionManager->getSessionBackend('FE');
$sessionManager->invalidateAllSessionsByUserId($sessionBackend, $userId);
}
}

0 comments on commit 4a41c71

Please sign in to comment.