From 4a41c71b8c7b4622633ee4b6ce1da065a7158760 Mon Sep 17 00:00:00 2001 From: Torben Hansen <derhansen@gmail.com> Date: Tue, 13 Dec 2022 10:20:03 +0100 Subject: [PATCH] [SECURITY] Destroy user sessions on password change 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> --- .../Classes/Authentication/PasswordReset.php | 13 +++++++++++++ .../Controller/PasswordRecoveryController.php | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/typo3/sysext/backend/Classes/Authentication/PasswordReset.php b/typo3/sysext/backend/Classes/Authentication/PasswordReset.php index 97c452f96942..6aec0a3a9818 100644 --- a/typo3/sysext/backend/Classes/Authentication/PasswordReset.php +++ b/typo3/sysext/backend/Classes/Authentication/PasswordReset.php @@ -39,6 +39,7 @@ use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction; 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; @@ -348,6 +349,8 @@ class PasswordReset implements LoggerAwareInterface ->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', @@ -498,4 +501,14 @@ class PasswordReset implements LoggerAwareInterface ->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); + } } diff --git a/typo3/sysext/felogin/Classes/Controller/PasswordRecoveryController.php b/typo3/sysext/felogin/Classes/Controller/PasswordRecoveryController.php index f76c5f8b54c2..c89c39b71196 100644 --- a/typo3/sysext/felogin/Classes/Controller/PasswordRecoveryController.php +++ b/typo3/sysext/felogin/Classes/Controller/PasswordRecoveryController.php @@ -24,6 +24,7 @@ use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException; 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; @@ -227,7 +228,9 @@ class PasswordRecoveryController extends AbstractLoginFormController 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')); @@ -331,4 +334,14 @@ class PasswordRecoveryController extends AbstractLoginFormController 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); + } } -- GitLab