diff --git a/includes/config/include.php b/includes/config/include.php index e70859422..e09848cda 100755 --- a/includes/config/include.php +++ b/includes/config/include.php @@ -28,7 +28,7 @@ define('TP_VERSION', '3.1.2'); define("UPGRADE_MIN_DATE", "1731422875"); -define('TP_VERSION_MINOR', '151'); +define('TP_VERSION_MINOR', '156'); define('TP_TOOL_NAME', 'Teampass'); define('TP_ONE_DAY_SECONDS', 86400); define('TP_ONE_WEEK_SECONDS', 604800); diff --git a/includes/core/login.oauth2.php b/includes/core/login.oauth2.php index 00e4c75ba..69bcd114b 100644 --- a/includes/core/login.oauth2.php +++ b/includes/core/login.oauth2.php @@ -30,13 +30,14 @@ */ use TeampassClasses\OAuth2Controller\OAuth2Controller; +use TeampassClasses\SessionManager\SessionManager; -session_start(); require_once __DIR__. '/../../includes/config/include.php'; require_once __DIR__.'/../../sources/main.functions.php'; // init loadClasses(); +$session = SessionManager::getSession(); // Création d'une instance du contrôleur $OAuth2 = new OAuth2Controller($SETTINGS); diff --git a/includes/libraries/csrfp/libs/csrf/csrfprotector.php b/includes/libraries/csrfp/libs/csrf/csrfprotector.php index f5d008c00..e94fc91b4 100755 --- a/includes/libraries/csrfp/libs/csrf/csrfprotector.php +++ b/includes/libraries/csrfp/libs/csrf/csrfprotector.php @@ -132,14 +132,6 @@ public static function init($length = null, $action = null, $logger = null) } - //SessionManager::getSession(); - // Start session in case its not, and unit test is not going on - if (session_id() == '' && !defined('__CSRFP_UNIT_TEST__')) { - //session_name('teampass_session'); - session_start(); - //$_SESSION['CPM'] = 1; - } - // Load configuration file and properties & Check locally for a // config.php then check for a config/csrf_config.php file in the // root folder for composer installations diff --git a/includes/libraries/teampassclasses/sessionmanager/src/EncryptedSessionProxy.php b/includes/libraries/teampassclasses/sessionmanager/src/EncryptedSessionProxy.php new file mode 100644 index 000000000..eb21a037e --- /dev/null +++ b/includes/libraries/teampassclasses/sessionmanager/src/EncryptedSessionProxy.php @@ -0,0 +1,86 @@ +. + * + * Certain components of this file may be under different licenses. For + * details, see the `licenses` directory or individual file headers. + * --- + * @file EncryptedSessionProxy.php + * @author Nils Laumaillé (nils@teampass.net) + * @copyright 2009-2024 Teampass.net + * @license GPL-3.0 + * @see https://www.teampass.net + */ + +use Defuse\Crypto\Crypto; +use Defuse\Crypto\Key; +use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; + +class EncryptedSessionProxy extends SessionHandlerProxy +{ + protected $handler; + private $key; + + /** + * Constructor. + * + * @param \SessionHandlerInterface $handler + * @param Key $key + */ + public function __construct( + \SessionHandlerInterface $handler, + Key $key + ) { + parent::__construct($handler); + $this->key = $key; + } + + /** + * Decrypt the session data after reading it from the session handler. + * + * @param string $id + * + * @return string + */ + public function read($id): string + { + $data = parent::read($id); + + if ($data !== '') { + return Crypto::decrypt($data, $this->key); + } + + return ''; + } + + /** + * Encrypt the session data before writing it to the session handler. + * + * @param string $id + * @param string $data + * + * @return bool + */ + public function write($id, $data): bool + { + $data = Crypto::encrypt($data, $this->key); + + return parent::write($id, $data); + } +} \ No newline at end of file diff --git a/includes/libraries/teampassclasses/sessionmanager/src/SessionManager.php b/includes/libraries/teampassclasses/sessionmanager/src/SessionManager.php index 525d8d16e..b962b2eab 100755 --- a/includes/libraries/teampassclasses/sessionmanager/src/SessionManager.php +++ b/includes/libraries/teampassclasses/sessionmanager/src/SessionManager.php @@ -30,6 +30,8 @@ use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Request; +use Defuse\Crypto\Key; +use TeampassClasses\SessionManager\EncryptedSessionProxy; class SessionManager { @@ -37,8 +39,16 @@ class SessionManager public static function getSession() { - if (null === self::$session) { - self::$session = new Session(); + if (null === self::$session) { + // Load the encryption key + $key = Key::loadFromAsciiSafeString(file_get_contents(SECUREPATH . "/" . SECUREFILE)); + + // Create an instance of EncryptedSessionProxy + $handler = new EncryptedSessionProxy(new \SessionHandler(), $key); + + // Create a new session with the encrypted session handler + self::$session = new Session(new \Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage([], $handler)); + if (session_status() === PHP_SESSION_NONE) { $request = Request::createFromGlobals(); $isSecure = $request->isSecure(); @@ -58,65 +68,65 @@ public static function getSession() } public static function addRemoveFromSessionArray($key, $values = [], $action = 'add') { - // Récupérer le tableau de la session + // Retrieve the array from the session $sessionArray = self::getSession()->get($key, []); foreach ($values as $value) { if ($action === 'add') { - // Ajouter la valeur au tableau + // Add the value to the array $sessionArray[] = $value; } elseif ($action === 'remove') { - // Trouver l'index de la valeur dans le tableau + // Find the index of the value in the array $index = array_search($value, $sessionArray); - // Si la valeur est trouvée dans le tableau, la supprimer + // If the value is found in the array, remove it if ($index !== false) { unset($sessionArray[$index]); } } } - // Réaffecter le tableau à la session + // Reassign the array to the session self::getSession()->set($key, $sessionArray); } public static function specificOpsOnSessionArray($key, $action = 'pop', $value = null) { - // Récupérer le tableau de la session + // Retrieve the array from the session $sessionArray = self::getSession()->get($key, []); if ($action === 'pop') { - // Supprimer la dernière valeur du tableau + // Remove the last value from the array array_pop($sessionArray); } elseif ($action === 'shift') { - // Supprimer la première valeur du tableau + // Remove the first value from the array array_shift($sessionArray); } elseif ($action === 'reset') { - // Réinitialiser le tableau + // Reset the array $sessionArray = []; } elseif ($action === 'unshift' && is_null($value) === false) { - // Ajouter une valeur au début du tableau + // Add a value to the beginning of the array array_unshift($sessionArray, $value); } - // Réaffecter le tableau à la session + // Reassign the array to the session self::getSession()->set($key, $sessionArray); } public static function addRemoveFromSessionAssociativeArray($key, $values = [], $action = 'add') { - // Récupérer le tableau de la session + // Retrieve the array from the session $sessionArray = self::getSession()->get($key, []); if ($action === 'add') { - // Ajouter la valeur au tableau + // Add the value to the array array_push($sessionArray, $values); } elseif ($action === 'remove') { - // Si la valeur existe dans le tableau, la supprimer + // If the value exists in the array, remove it if (($key = array_search($values, $sessionArray)) !== false) { unset($sessionArray[$key]); } } - // Réaffecter le tableau à la session + // Reassign the array to the session self::getSession()->set($key, $sessionArray); } @@ -124,7 +134,7 @@ public static function getCookieValue($cookieName) { $request = Request::createFromGlobals(); - // Vérifier si le cookie existe + // Check if the cookie exists if ($request->cookies->has($cookieName)) { return $request->cookies->get($cookieName); } diff --git a/install/install.queries.php b/install/install.queries.php index bc0e6df8a..c01aee4c8 100755 --- a/install/install.queries.php +++ b/install/install.queries.php @@ -31,13 +31,13 @@ use Defuse\Crypto\Key; use Defuse\Crypto\Crypto; use Defuse\Crypto\Exception as CryptoException; -use EZimuel\PHPSecureSession; use Hackzilla\PasswordGenerator\Generator\ComputerPasswordGenerator; use Hackzilla\PasswordGenerator\RandomGenerator\Php7RandomGenerator; use TeampassClasses\SuperGlobal\SuperGlobal; use TeampassClasses\Language\Language; use TeampassClasses\PasswordManager\PasswordManager; use TeampassClasses\ConfigManager\ConfigManager; +use TeampassClasses\SessionManager\SessionManager; use Encryption\Crypt\aesctr; // Do initial test @@ -58,11 +58,9 @@ // init loadClasses('DB'); +$session = SessionManager::getSession(); $superGlobal = new SuperGlobal(); $lang = new Language(); -if (session_status() == PHP_SESSION_NONE) { - session_start(); -} // Load config $configManager = new ConfigManager(); diff --git a/install/migrate_users_to_v3.php b/install/migrate_users_to_v3.php index cd1697122..c00d0c6d4 100755 --- a/install/migrate_users_to_v3.php +++ b/install/migrate_users_to_v3.php @@ -27,12 +27,16 @@ * @see https://www.teampass.net */ +use TeampassClasses\SessionManager\SessionManager; set_time_limit(600); - require_once './libs/SecureHandler.php'; -session_name('teampass_session'); -session_start(); +require_once '../sources/main.functions.php'; + +// init +loadClasses(); +$session = SessionManager::getSession(); + error_reporting(E_ERROR | E_PARSE); $_SESSION['db_encoding'] = 'utf8'; $_SESSION['CPM'] = 1; diff --git a/install/upgrade.php b/install/upgrade.php index 90f94ae9e..8032d4bec 100755 --- a/install/upgrade.php +++ b/install/upgrade.php @@ -26,6 +26,7 @@ * @see https://www.teampass.net */ +use TeampassClasses\SessionManager\SessionManager; header('X-XSS-Protection: 1; mode=block'); header('X-Frame-Options: SameOrigin'); @@ -42,7 +43,12 @@ ini_set('session.cookie_secure', 0); require_once './libs/SecureHandler.php'; -session_start(); +require_once '../sources/main.functions.php'; + +// init +loadClasses(); +$session = SessionManager::getSession(); + //Session teampass tag $_SESSION['CPM'] = 1; define('MIN_PHP_VERSION', 8.1); diff --git a/install/upgrade_scripts_manager.php b/install/upgrade_scripts_manager.php index 80e2bbcfd..16a6efe44 100755 --- a/install/upgrade_scripts_manager.php +++ b/install/upgrade_scripts_manager.php @@ -26,12 +26,16 @@ * @see https://www.teampass.net */ +use TeampassClasses\SessionManager\SessionManager; set_time_limit(600); - require_once './libs/SecureHandler.php'; -session_name('teampass_session'); -session_start(); +require_once '../sources/main.functions.php'; + +// init +loadClasses(); +$session = SessionManager::getSession(); + error_reporting(E_ERROR | E_PARSE); $_SESSION['db_encoding'] = 'utf8'; $_SESSION['CPM'] = 1; diff --git a/sources/identify.php b/sources/identify.php index e2e2b4dec..b105ba7de 100755 --- a/sources/identify.php +++ b/sources/identify.php @@ -30,15 +30,11 @@ */ use voku\helper\AntiXSS; -use EZimuel\PHPSecureSession; use TeampassClasses\SessionManager\SessionManager; use Symfony\Component\HttpFoundation\Request as SymfonyRequest; use TeampassClasses\Language\Language; use TeampassClasses\PerformChecks\PerformChecks; use TeampassClasses\ConfigManager\ConfigManager; -use LdapRecord\Connection; -use LdapRecord\Container; -use LdapRecord\Auth\Events\Failed; use TeampassClasses\NestedTree\NestedTree; use TeampassClasses\PasswordManager\PasswordManager; use Duo\DuoUniversal\Client; diff --git a/sources/oauth.php b/sources/oauth.php index 2392644e3..aed0b848e 100644 --- a/sources/oauth.php +++ b/sources/oauth.php @@ -1,11 +1,13 @@ . + * + * Certain components of this file may be under different licenses. For + * details, see the `licenses` directory or individual file headers. + * --- + * @file EncryptedSessionProxy.php + * @author Nils Laumaillé (nils@teampass.net) + * @copyright 2009-2024 Teampass.net + * @license GPL-3.0 + * @see https://www.teampass.net + */ + +use Defuse\Crypto\Crypto; +use Defuse\Crypto\Key; +use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; + +class EncryptedSessionProxy extends SessionHandlerProxy +{ + protected $handler; + private $key; + + /** + * Constructor. + * + * @param \SessionHandlerInterface $handler + * @param Key $key + */ + public function __construct( + \SessionHandlerInterface $handler, + Key $key + ) { + parent::__construct($handler); + $this->key = $key; + } + + /** + * Decrypt the session data after reading it from the session handler. + * + * @param string $id + * + * @return string + */ + public function read($id): string + { + $data = parent::read($id); + + if ($data !== '' && preg_match('/^def/', $data)) { + return Crypto::decrypt($data, $this->key); + } + + return ''; + } + + /** + * Encrypt the session data before writing it to the session handler. + * + * @param string $id + * @param string $data + * + * @return bool + */ + public function write($id, $data): bool + { + $data = Crypto::encrypt($data, $this->key); + + return parent::write($id, $data); + } +} \ No newline at end of file diff --git a/vendor/teampassclasses/sessionmanager/src/SessionManager.php b/vendor/teampassclasses/sessionmanager/src/SessionManager.php index 525d8d16e..b962b2eab 100755 --- a/vendor/teampassclasses/sessionmanager/src/SessionManager.php +++ b/vendor/teampassclasses/sessionmanager/src/SessionManager.php @@ -30,6 +30,8 @@ use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Request; +use Defuse\Crypto\Key; +use TeampassClasses\SessionManager\EncryptedSessionProxy; class SessionManager { @@ -37,8 +39,16 @@ class SessionManager public static function getSession() { - if (null === self::$session) { - self::$session = new Session(); + if (null === self::$session) { + // Load the encryption key + $key = Key::loadFromAsciiSafeString(file_get_contents(SECUREPATH . "/" . SECUREFILE)); + + // Create an instance of EncryptedSessionProxy + $handler = new EncryptedSessionProxy(new \SessionHandler(), $key); + + // Create a new session with the encrypted session handler + self::$session = new Session(new \Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage([], $handler)); + if (session_status() === PHP_SESSION_NONE) { $request = Request::createFromGlobals(); $isSecure = $request->isSecure(); @@ -58,65 +68,65 @@ public static function getSession() } public static function addRemoveFromSessionArray($key, $values = [], $action = 'add') { - // Récupérer le tableau de la session + // Retrieve the array from the session $sessionArray = self::getSession()->get($key, []); foreach ($values as $value) { if ($action === 'add') { - // Ajouter la valeur au tableau + // Add the value to the array $sessionArray[] = $value; } elseif ($action === 'remove') { - // Trouver l'index de la valeur dans le tableau + // Find the index of the value in the array $index = array_search($value, $sessionArray); - // Si la valeur est trouvée dans le tableau, la supprimer + // If the value is found in the array, remove it if ($index !== false) { unset($sessionArray[$index]); } } } - // Réaffecter le tableau à la session + // Reassign the array to the session self::getSession()->set($key, $sessionArray); } public static function specificOpsOnSessionArray($key, $action = 'pop', $value = null) { - // Récupérer le tableau de la session + // Retrieve the array from the session $sessionArray = self::getSession()->get($key, []); if ($action === 'pop') { - // Supprimer la dernière valeur du tableau + // Remove the last value from the array array_pop($sessionArray); } elseif ($action === 'shift') { - // Supprimer la première valeur du tableau + // Remove the first value from the array array_shift($sessionArray); } elseif ($action === 'reset') { - // Réinitialiser le tableau + // Reset the array $sessionArray = []; } elseif ($action === 'unshift' && is_null($value) === false) { - // Ajouter une valeur au début du tableau + // Add a value to the beginning of the array array_unshift($sessionArray, $value); } - // Réaffecter le tableau à la session + // Reassign the array to the session self::getSession()->set($key, $sessionArray); } public static function addRemoveFromSessionAssociativeArray($key, $values = [], $action = 'add') { - // Récupérer le tableau de la session + // Retrieve the array from the session $sessionArray = self::getSession()->get($key, []); if ($action === 'add') { - // Ajouter la valeur au tableau + // Add the value to the array array_push($sessionArray, $values); } elseif ($action === 'remove') { - // Si la valeur existe dans le tableau, la supprimer + // If the value exists in the array, remove it if (($key = array_search($values, $sessionArray)) !== false) { unset($sessionArray[$key]); } } - // Réaffecter le tableau à la session + // Reassign the array to the session self::getSession()->set($key, $sessionArray); } @@ -124,7 +134,7 @@ public static function getCookieValue($cookieName) { $request = Request::createFromGlobals(); - // Vérifier si le cookie existe + // Check if the cookie exists if ($request->cookies->has($cookieName)) { return $request->cookies->get($cookieName); }