?
avatar feltkamptv
feltkamptv
26 Mar 2018

If a Joomla user account has been compromised and is logged in and being used on a different computer, changing the password does not help to log the attacker out. It would be nice to force a session change and/or user logout after a password change.

I use the DB for sessions and I could solve it with a plugin and the onUserAfterSave function, which would delete all sessions in the DB where user id is X and session id not is the current session id. But I thought posting this here first, maybe this should be integrated in Joomla?

Steps to reproduce the issue

  1. Login to Joomla on Chrome.
  2. Login again on Firefox
  3. Go to change password and change the password on Firefox.
  4. Reload Chrome account tab.
  5. Session is still alive on Chrome even after password change.

System information

Joomla version: 3.8.6
PHP: 7.1
MySQL: 5.6

This bug was reported to us by a security researcher.

Votes

# of Users Experiencing Issue
2/2
Average Importance Score
4.50

avatar feltkamptv feltkamptv - open - 26 Mar 2018
avatar joomla-cms-bot joomla-cms-bot - change - 26 Mar 2018
Labels Added: ?
avatar joomla-cms-bot joomla-cms-bot - labeled - 26 Mar 2018
avatar brianteeman
brianteeman - comment - 26 Mar 2018

You can force a user to be logged out by clicking on the X next to their name in the logged in users module present on your admin dashboard

chrome_2018-03-26_11-58-08

avatar franz-wohlkoenig franz-wohlkoenig - change - 26 Mar 2018
Status New Discussion
avatar franz-wohlkoenig franz-wohlkoenig - change - 26 Mar 2018
Category Authentication
avatar feltkamptv
feltkamptv - comment - 26 Mar 2018

Yes, I understand it is possible to logout a user manually, but that is not the issue. We have a site with millions of hits every hour and over 100.000 registered users. I am not looking to manually logout users, I need to implement automatically logout on password change. Please read the posted issue carefully.

avatar brianteeman
brianteeman - comment - 26 Mar 2018

(it you have such a busy site you really must upgrade the version of php. PHP 7.* is considerably faster)

avatar mbabker
mbabker - comment - 26 Mar 2018

This shouldn't be an arbitrary core functionality. As you pointed out, a simple plugin listening to onUserAfterSave can handle this.

There is one issue in your approach if not using the database session handler. It won't actually destroy the session, just the optional metadata record. You need something like this to ensure all sessions are destroyed:

$query = $this->db->getQuery(true)
	->select('session_id)')
	->from('#__session')
	->where($this->db->quoteName('userid') . ' = ' . (int) $user['id']);

if (!$sharedSessions)
{
	$query->where($this->db->quoteName('client_id') . ' = ' . (int) $this->app->getClientId());
}

try
{
	$sessions = $this->db->setQuery($query)->loadColumn();
}
catch (JDatabaseExceptionExecuting $e)
{
	return false;
}

$handler = JFactory::getConfig()->get('session_handler' , 'database');
$storage = JSessionStorage::getInstance($handler);

foreach ($sessions as $session)
{
	$storage->destroy($session);
}
avatar feltkamptv feltkamptv - change - 26 Mar 2018
Status Discussion Closed
Closed_Date 0000-00-00 00:00:00 2018-03-26 12:17:41
Closed_By feltkamptv
avatar feltkamptv feltkamptv - close - 26 Mar 2018
avatar feltkamptv
feltkamptv - comment - 26 Mar 2018

I will implement this then with a plugin. Thanks again for the fast response!

avatar feltkamptv
feltkamptv - comment - 26 Mar 2018

I am now using this code in my user plugin and it seems to work:

public function onUserAfterSave($user, $isnew, $success, $msg)
{
	if(!empty($user['password_clear']) && !$isnew){
		$session = JFactory::getSession();
		$session_id = $session->getId();
		
		$query = $this->db->getQuery(true)
			->select('session_id')
			->from('#__session')
			->where($this->db->quoteName('userid') . ' = ' . (int) $user['id'])
			->where($this->db->quoteName('session_id') . ' != ' . $this->db->quote($session_id));
			
		try{
			$sessions = $this->db->setQuery($query)->loadColumn();
		}catch (JDatabaseExceptionExecuting $e){
			return false;
		}
			
		if(count($sessions) > 0){
			$handler = JFactory::getConfig()->get('session_handler' , 'database');
			$storage = JSessionStorage::getInstance($handler);

			foreach($sessions as $session){
				$storage->destroy($session);
			}
		}//count sessions
	}//if not new and password changed
	return true;
}
avatar innato
innato - comment - 10 Sep 2019

If this would be implemented, what if both the 'compromisor' and you are logged into the same account? The compromisor changes the password, your session will be aborted and you won't be able to log in...
Or do I miss something?
PS: Sorry for commenting on this old thread.

avatar zero-24
zero-24 - comment - 11 Sep 2019

If this would be implemented,

it is not implemented ;)

Or do I miss something?

You are correct this would be the case where should joomla know who is compromisor and the original user? ;)

avatar c-schmitz
c-schmitz - comment - 14 May 2024

I would like to kindly ask to reconsider this decision.
OWASP clearly states to renew the session ID after a password change: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#renew-the-session-id-after-any-privilege-level-change

It is also not a very costly thing to do. Usually, it is 1–2 lines of code and has no effect on the user experience.

For a detailed discussion on the matter, also check out https://security.stackexchange.com/questions/266777/session-regeneration-after-password-change


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/19994.

Add a Comment

Login with GitHub to post a comment