From 6359259dbb1e8d5b569f569a7089abffd9259d30 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Mon, 1 Mar 2021 15:24:18 +0300 Subject: simplify internal authentication code and bump default algo to SSHA-512 --- classes/auth/base.php | 4 ++-- classes/pref/prefs.php | 24 +++---------------- classes/pref/users.php | 22 +++++++---------- classes/rpc.php | 2 +- classes/userhelper.php | 65 ++++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 75 insertions(+), 42 deletions(-) (limited to 'classes') diff --git a/classes/auth/base.php b/classes/auth/base.php index f18cc2d2d..9b2f630c0 100644 --- a/classes/auth/base.php +++ b/classes/auth/base.php @@ -23,8 +23,8 @@ abstract class Auth_Base extends Plugin implements IAuthModule { if (!$password) $password = make_password(); - $salt = substr(bin2hex(get_random_bytes(125)), 0, 250); - $pwd_hash = encrypt_password($password, $salt, true); + $salt = UserHelper::get_salt(); + $pwd_hash = UserHelper::hash_password($password, $salt, UserHelper::HASH_ALGOS[0]); $sth = $this->pdo->prepare("INSERT INTO ttrss_users (login,access_level,last_login,created,pwd_hash,salt) diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php index 5fe4f1bbf..f61f0f038 100644 --- a/classes/pref/prefs.php +++ b/classes/pref/prefs.php @@ -1038,19 +1038,6 @@ class Pref_Prefs extends Handler_Protected { } } - static function _is_default_password() { - $authenticator = PluginHost::getInstance()->get_plugin($_SESSION["auth_module"]); - - if ($authenticator && - method_exists($authenticator, "check_password") && - $authenticator->check_password($_SESSION["uid"], "password")) { - - return true; - } - - return false; - } - function otpdisable() { $password = clean($_REQUEST["password"]); @@ -1404,12 +1391,6 @@ class Pref_Prefs extends Handler_Protected { _encrypt_app_password($new_password); + $new_salt = UserHelper::get_salt(); + $new_password_hash = UserHelper::hash_password($new_password, $new_salt, UserHelper::HASH_ALGOS[0]); print_warning(T_sprintf("Generated password %s for %s. Please remember it for future reference.", $new_password, $title)); @@ -1432,7 +1414,7 @@ class Pref_Prefs extends Handler_Protected { VALUES (?, ?, ?, NOW(), ?)"); - $sth->execute([$title, $new_password_hash, Auth_Base::AUTH_SERVICE_API, $_SESSION['uid']]); + $sth->execute([$title, "$new_password_hash:$new_salt", Auth_Base::AUTH_SERVICE_API, $_SESSION['uid']]); $this->appPasswordList(); } diff --git a/classes/pref/users.php b/classes/pref/users.php index 13f808cb3..111cabdca 100644 --- a/classes/pref/users.php +++ b/classes/pref/users.php @@ -107,7 +107,7 @@ class Pref_Users extends Handler_Administrative { function editSave() { $login = clean($_REQUEST["login"]); - $uid = clean($_REQUEST["id"]); + $uid = (int) clean($_REQUEST["id"]); $access_level = (int) clean($_REQUEST["access_level"]); $email = clean($_REQUEST["email"]); $password = clean($_REQUEST["password"]); @@ -118,19 +118,13 @@ class Pref_Users extends Handler_Administrative { // forbid renaming admin if ($uid == 1) $login = "admin"; - if ($password) { - $salt = substr(bin2hex(get_random_bytes(125)), 0, 250); - $pwd_hash = encrypt_password($password, $salt, true); - $pass_query_part = "pwd_hash = ".$this->pdo->quote($pwd_hash).", - salt = ".$this->pdo->quote($salt).","; - } else { - $pass_query_part = ""; - } - - $sth = $this->pdo->prepare("UPDATE ttrss_users SET $pass_query_part login = LOWER(?), - access_level = ?, email = ?, otp_enabled = false WHERE id = ?"); + $sth = $this->pdo->prepare("UPDATE ttrss_users SET login = LOWER(?), + access_level = ?, email = ?, otp_enabled = false WHERE id = ?"); $sth->execute([$login, $access_level, $email, $uid]); + if ($password) { + UserHelper::reset_password($uid, false, $password); + } } function remove() { @@ -153,8 +147,8 @@ class Pref_Users extends Handler_Administrative { function add() { $login = clean($_REQUEST["login"]); $tmp_user_pwd = make_password(); - $salt = substr(bin2hex(get_random_bytes(125)), 0, 250); - $pwd_hash = encrypt_password($tmp_user_pwd, $salt, true); + $salt = UserHelper::get_salt(); + $pwd_hash = UserHelper::hash_password($tmp_user_pwd, $salt, UserHelper::HASH_ALGOS[0]); if (!$login) return; // no blank usernames diff --git a/classes/rpc.php b/classes/rpc.php index 65612ec34..633e3a86e 100755 --- a/classes/rpc.php +++ b/classes/rpc.php @@ -442,7 +442,7 @@ class RPC extends Handler_Protected { $params["default_view_limit"] = (int) get_pref(Prefs::_DEFAULT_VIEW_LIMIT); $params["default_view_order_by"] = get_pref(Prefs::_DEFAULT_VIEW_ORDER_BY); $params["bw_limit"] = (int) $_SESSION["bw_limit"]; - $params["is_default_pw"] = Pref_Prefs::_is_default_password(); + $params["is_default_pw"] = UserHelper::is_default_password(); $params["label_base_index"] = LABEL_BASE_INDEX; $theme = get_pref(Prefs::USER_CSS_THEME); diff --git a/classes/userhelper.php b/classes/userhelper.php index 44406b959..e3f39a7f8 100644 --- a/classes/userhelper.php +++ b/classes/userhelper.php @@ -3,6 +3,20 @@ use OTPHP\TOTP; class UserHelper { + const HASH_ALGO_SSHA512 = 'SSHA-512'; + const HASH_ALGO_SSHA256 = 'SSHA-256'; + const HASH_ALGO_MODE2 = 'MODE2'; + const HASH_ALGO_SHA1X = 'SHA1X'; + const HASH_ALGO_SHA1 = 'SHA1'; + + const HASH_ALGOS = [ + self::HASH_ALGO_SSHA512, + self::HASH_ALGO_SSHA256, + self::HASH_ALGO_MODE2, + self::HASH_ALGO_SHA1X, + self::HASH_ALGO_SHA1 + ]; + static function authenticate(string $login = null, string $password = null, bool $check_only = false, string $service = null) { if (!Config::get(Config::SINGLE_USER_MODE)) { $user_id = false; @@ -190,7 +204,11 @@ class UserHelper { session_commit(); } - static function reset_password($uid, $format_output = false) { + static function get_salt() { + return substr(bin2hex(get_random_bytes(125)), 0, 250); + } + + static function reset_password($uid, $format_output = false, $new_password = "") { $pdo = Db::pdo(); @@ -201,10 +219,10 @@ class UserHelper { $login = $row["login"]; - $new_salt = substr(bin2hex(get_random_bytes(125)), 0, 250); - $tmp_user_pwd = make_password(); + $new_salt = self::get_salt(); + $tmp_user_pwd = $new_password ? $new_password : make_password(); - $pwd_hash = encrypt_password($tmp_user_pwd, $new_salt, true); + $pwd_hash = self::hash_password($tmp_user_pwd, $new_salt, self::HASH_ALGOS[0]); $sth = $pdo->prepare("UPDATE ttrss_users SET pwd_hash = ?, salt = ?, otp_enabled = false @@ -276,4 +294,43 @@ class UserHelper { return null; } + + static function is_default_password() { + $authenticator = PluginHost::getInstance()->get_plugin($_SESSION["auth_module"]); + + if ($authenticator && + method_exists($authenticator, "check_password") && + $authenticator->check_password($_SESSION["uid"], "password")) { + + return true; + } + return false; + } + + static function hash_password(string $pass, string $salt, string $algo) { + $pass_hash = ""; + + switch ($algo) { + case self::HASH_ALGO_SHA1: + $pass_hash = sha1($pass); + break; + case self::HASH_ALGO_SHA1X: + $pass_hash = sha1("$salt:$pass"); + break; + case self::HASH_ALGO_MODE2: + case self::HASH_ALGO_SSHA256: + $pass_hash = hash('sha256', $salt . $pass); + break; + case self::HASH_ALGO_SSHA512: + $pass_hash = hash('sha512', $salt . $pass); + break; + default: + user_error("hash_password: unknown hash algo: $algo", E_USER_ERROR); + } + + if ($pass_hash) + return "$algo:$pass_hash"; + else + return false; + } } -- cgit v1.2.3