diff --git a/libraries/classes/Plugins/Auth/AuthenticationCookie.php b/libraries/classes/Plugins/Auth/AuthenticationCookie.php index fe9a9a86af..5831c9c0e4 100644 --- a/libraries/classes/Plugins/Auth/AuthenticationCookie.php +++ b/libraries/classes/Plugins/Auth/AuthenticationCookie.php @@ -8,18 +8,18 @@ */ namespace PhpMyAdmin\Plugins\Auth; -use phpseclib\Crypt; +use PhpMyAdmin\Config; +use PhpMyAdmin\Core; use PhpMyAdmin\LanguageManager; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins\AuthenticationPlugin; use PhpMyAdmin\Response; +use PhpMyAdmin\Session; use PhpMyAdmin\Util; -use PhpMyAdmin\Config; -use PhpMyAdmin\Core; -use ReCaptcha; use PhpMyAdmin\Url; +use phpseclib\Crypt; +use ReCaptcha; -require_once './libraries/session.lib.php'; require_once './libraries/hash.lib.php'; /** @@ -376,7 +376,7 @@ class AuthenticationCookie extends AuthenticationPlugin } $GLOBALS['pma_auth_server'] = Core::sanitizeMySQLHost($_REQUEST['pma_servername']); } - PMA_secureSession(); + Session::secure(); return true; } diff --git a/libraries/classes/Session.php b/libraries/classes/Session.php new file mode 100644 index 0000000000..b4006b5e28 --- /dev/null +++ b/libraries/classes/Session.php @@ -0,0 +1,227 @@ +getMessage()) + ); + } + + /* + * Session initialization is done before selecting language, so we + * can not use translations here. + */ + Core::fatalError( + 'Error during session start; please check your PHP and/or ' + . 'webserver log file and configure your PHP ' + . 'installation properly. Also ensure that cookies are enabled ' + . 'in your browser.' + . '

' + . implode('

', $messages) + ); + } + + /** + * Set up session + * + * @param PhpMyAdmin\Config $config Configuration handler + * @param PhpMyAdmin\ErrorHandler $errorHandler Error handler + * @return void + */ + public static function setUp(Config $config, ErrorHandler $errorHandler) + { + // verify if PHP supports session, die if it does not + if (!@function_exists('session_name')) { + Core::warnMissingExtension('session', true); + } elseif (! empty(ini_get('session.auto_start')) + && session_name() != 'phpMyAdmin' + && !empty(session_id())) { + // Do not delete the existing non empty session, it might be used by + // other applications; instead just close it. + if (empty($_SESSION)) { + // Ignore errors as this might have been destroyed in other + // request meanwhile + @session_destroy(); + } elseif (function_exists('session_abort')) { + // PHP 5.6 and newer + session_abort(); + } else { + session_write_close(); + } + } + + // session cookie settings + session_set_cookie_params( + 0, $config->getRootPath(), + '', $config->isHttps(), true + ); + + // cookies are safer (use @ini_set() in case this function is disabled) + @ini_set('session.use_cookies', 'true'); + + // optionally set session_save_path + $path = $config->get('SessionSavePath'); + if (!empty($path)) { + session_save_path($path); + } + + // use cookies only + @ini_set('session.use_only_cookies', '1'); + // strict session mode (do not accept random string as session ID) + @ini_set('session.use_strict_mode', '1'); + // make the session cookie HttpOnly + @ini_set('session.cookie_httponly', '1'); + // do not force transparent session ids + @ini_set('session.use_trans_sid', '0'); + + // delete session/cookies when browser is closed + @ini_set('session.cookie_lifetime', '0'); + + // warn but don't work with bug + @ini_set('session.bug_compat_42', 'false'); + @ini_set('session.bug_compat_warn', 'true'); + + // use more secure session ids + @ini_set('session.hash_function', '1'); + + // some pages (e.g. stylesheet) may be cached on clients, but not in shared + // proxy servers + session_cache_limiter('private'); + + $session_name = 'phpMyAdmin'; + @session_name($session_name); + + // Restore correct sesion ID (it might have been reset by auto started session + if (isset($_COOKIE['phpMyAdmin'])) { + session_id($_COOKIE['phpMyAdmin']); + } + + // on first start of session we check for errors + // f.e. session dir cannot be accessed - session file not created + $orig_error_count = $errorHandler->countErrors(false); + + $session_result = session_start(); + + if ($session_result !== true + || $orig_error_count != $errorHandler->countErrors(false) + ) { + setcookie($session_name, '', 1); + $errors = $errorHandler->sliceErrors($orig_error_count); + self::sessionFailed($errors); + } + unset($orig_error_count, $session_result); + + /** + * Disable setting of session cookies for further session_start() calls. + */ + @ini_set('session.use_cookies', 'true'); + + /** + * Token which is used for authenticating access queries. + * (we use "space PMA_token space" to prevent overwriting) + */ + if (empty($_SESSION[' PMA_token '])) { + self::generateToken(); + + /** + * Check for disk space on session storage by trying to write it. + * + * This seems to be most reliable approach to test if sessions are working, + * otherwise the check would fail with custom session backends. + */ + $orig_error_count = $errorHandler->countErrors(); + session_write_close(); + if ($errorHandler->countErrors() > $orig_error_count) { + $errors = $errorHandler->sliceErrors($orig_error_count); + self::sessionFailed($errors); + } + session_start(); + if (empty($_SESSION[' PMA_token '])) { + Core::fatalError( + 'Failed to store CSRF token in session! ' . + 'Probably sessions are not working properly.' + ); + } + } + } +} diff --git a/libraries/common.inc.php b/libraries/common.inc.php index 2d9cbbad2d..7f46dea77b 100644 --- a/libraries/common.inc.php +++ b/libraries/common.inc.php @@ -34,17 +34,18 @@ use PhpMyAdmin\Config; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\ErrorHandler; -use PhpMyAdmin\Message; -use PhpMyAdmin\Plugins\AuthenticationPlugin; use PhpMyAdmin\DbList; -use PhpMyAdmin\ThemeManager; -use PhpMyAdmin\Tracker; -use PhpMyAdmin\Response; -use PhpMyAdmin\TypesMySQL; -use PhpMyAdmin\Util; +use PhpMyAdmin\ErrorHandler; use PhpMyAdmin\LanguageManager; use PhpMyAdmin\Logging; +use PhpMyAdmin\Message; +use PhpMyAdmin\Plugins\AuthenticationPlugin; +use PhpMyAdmin\Response; +use PhpMyAdmin\Session; +use PhpMyAdmin\ThemeManager; +use PhpMyAdmin\Tracker; +use PhpMyAdmin\TypesMySQL; +use PhpMyAdmin\Util; /** * block attempts to directly run this script @@ -258,7 +259,7 @@ if (isset($_COOKIE)) { /** * include session handling after the globals, to prevent overwriting */ -require './libraries/session.inc.php'; +Session::setUp($GLOBALS['PMA_Config'], $GLOBALS['error_handler']); /** * init some variables LABEL_variables_init @@ -670,7 +671,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { if (! $auth_plugin->authCheck()) { /* Force generating of new session on login */ - PMA_secureSession(); + Session::secure(); $auth_plugin->auth(); } else { $auth_plugin->authSetUser(); diff --git a/libraries/session.inc.php b/libraries/session.inc.php deleted file mode 100644 index cf32c779ce..0000000000 --- a/libraries/session.inc.php +++ /dev/null @@ -1,185 +0,0 @@ -getRootPath(), - '', $GLOBALS['PMA_Config']->isHttps(), true -); - -// cookies are safer (use @ini_set() in case this function is disabled) -@ini_set('session.use_cookies', 'true'); - -// optionally set session_save_path -$path = $GLOBALS['PMA_Config']->get('SessionSavePath'); -if (!empty($path)) { - session_save_path($path); -} - -// use cookies only -@ini_set('session.use_only_cookies', '1'); -// strict session mode (do not accept random string as session ID) -@ini_set('session.use_strict_mode', '1'); -// make the session cookie HttpOnly -@ini_set('session.cookie_httponly', '1'); -// do not force transparent session ids -@ini_set('session.use_trans_sid', '0'); - -// delete session/cookies when browser is closed -@ini_set('session.cookie_lifetime', '0'); - -// warn but don't work with bug -@ini_set('session.bug_compat_42', 'false'); -@ini_set('session.bug_compat_warn', 'true'); - -// use more secure session ids -@ini_set('session.hash_function', '1'); - -// some pages (e.g. stylesheet) may be cached on clients, but not in shared -// proxy servers -session_cache_limiter('private'); - -// start the session -// on some servers (for example, sourceforge.net), we get a permission error -// on the session data directory, so I add some "@" - -/** - * Session failed function - * - * @param array $errors PhpMyAdmin\ErrorHandler array - * - * @return void - */ -function PMA_sessionFailed($errors) -{ - $messages = array(); - foreach ($errors as $error) { - /* - * Remove path from open() in error message to avoid path disclossure - * - * This can happen with PHP 5 when nonexisting session ID is provided, - * since PHP 7, session existence is checked first. - * - * This error can also happen in case of session backed error (eg. - * read only filesystem) on any PHP version. - * - * The message string is currently hardcoded in PHP, so hopefully it - * will not change in future. - */ - $messages[] = preg_replace( - '/open\(.*, O_RDWR\)/', - 'open(SESSION_FILE, O_RDWR)', - htmlspecialchars($error->getMessage()) - ); - } - - /* - * Session initialization is done before selecting language, so we - * can not use translations here. - */ - Core::fatalError( - 'Error during session start; please check your PHP and/or ' - . 'webserver log file and configure your PHP ' - . 'installation properly. Also ensure that cookies are enabled ' - . 'in your browser.' - . '

' - . implode('

', $messages) - ); -} - -// See bug #1538132. This would block normal behavior on a cluster -//ini_set('session.save_handler', 'files'); - -$session_name = 'phpMyAdmin'; -@session_name($session_name); - -// Restore correct sesion ID (it might have been reset by auto started session -if (isset($_COOKIE['phpMyAdmin'])) { - session_id($_COOKIE['phpMyAdmin']); -} - -// on first start of session we check for errors -// f.e. session dir cannot be accessed - session file not created -$orig_error_count = $GLOBALS['error_handler']->countErrors(false); - -$session_result = session_start(); - -if ($session_result !== true - || $orig_error_count != $GLOBALS['error_handler']->countErrors(false) -) { - setcookie($session_name, '', 1); - $errors = $GLOBALS['error_handler']->sliceErrors($orig_error_count); - PMA_sessionFailed($errors); -} -unset($orig_error_count, $session_result); - -/** - * Disable setting of session cookies for further session_start() calls. - */ -@ini_set('session.use_cookies', 'true'); - -/** - * Token which is used for authenticating access queries. - * (we use "space PMA_token space" to prevent overwriting) - */ -if (empty($_SESSION[' PMA_token '])) { - PMA_generateToken(); - - /** - * Check for disk space on session storage by trying to write it. - * - * This seems to be most reliable approach to test if sessions are working, - * otherwise the check would fail with custom session backends. - */ - $orig_error_count = $GLOBALS['error_handler']->countErrors(); - session_write_close(); - if ($GLOBALS['error_handler']->countErrors() > $orig_error_count) { - $errors = $GLOBALS['error_handler']->sliceErrors($orig_error_count); - PMA_sessionFailed($errors); - } - session_start(); - if (empty($_SESSION[' PMA_token '])) { - Core::fatalError( - 'Failed to store CSRF token in session! ' . - 'Probably sessions are not working properly.' - ); - } -} diff --git a/libraries/session.lib.php b/libraries/session.lib.php deleted file mode 100644 index f38e14216e..0000000000 --- a/libraries/session.lib.php +++ /dev/null @@ -1,47 +0,0 @@ -