From 8088d92bbbe616b785ac1d26d03b8da417c6bd1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Labate?= Date: Mon, 15 Jan 2018 00:33:25 +0100 Subject: [PATCH 1/2] NEW Add password_hash as hash algorithm --- htdocs/core/lib/security.lib.php | 30 +++++++++++++++++++++++- htdocs/core/login/functions_dolibarr.php | 4 +--- htdocs/install/step5.php | 2 +- htdocs/user/passwordforgotten.php | 3 +-- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php index 71fcdf33bb3..88e6ebb7af5 100644 --- a/htdocs/core/lib/security.lib.php +++ b/htdocs/core/lib/security.lib.php @@ -81,6 +81,9 @@ function dol_hash($chain, $type='0') { global $conf; + // No need to add salt for password_hash + if ($type == '0' && ! empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash') return password_hash($chain, PASSWORD_DEFAULT); + // Salt value if (! empty($conf->global->MAIN_SECURITY_SALT)) $chain=$conf->global->MAIN_SECURITY_SALT.$chain; @@ -96,6 +99,32 @@ function dol_hash($chain, $type='0') return md5($chain); } +/** + * Compute a hash and compare it to the given one + * For backward compatibility reasons, if the hash is not in the password_hash format, we will try to match against md5 and sha1md5 + * If constant MAIN_SECURITY_HASH_ALGO is defined, we use this function as hashing function. + * If constant MAIN_SECURITY_SALT is defined, we use it as a salt. + * + * @param string $chain String to hash + * @param string $hash hash to compare + * @param string $type Type of hash ('0':auto, '1':sha1, '2':sha1+md5, '3':md5, '4':md5 for OpenLdap, '5':sha256). Use '3' here, if hash is not needed for security purpose, for security need, prefer '0'. + * @return bool True if the computed hash is the same as the given one + */ +function dol_verifyHash($chain, $hash, $type='0') +{ + global $conf; + + if ($type == '0' && ! empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash') { + if ($hash[0] == '$') return password_verify($chain, $hash); + else if(strlen($hash) == 32) return dol_verifyHash($chain, $hash, '3'); // md5 + else if(strlen($hash) == 40) return dol_verifyHash($chain, $hash, '2'); // sha1md5 + + return false; + } + + return dol_hash($chain, $type) == $hash; +} + /** * Check permissions of a user to show a page and an object. Check read permission. @@ -606,4 +635,3 @@ function accessforbidden($message='',$printheader=1,$printfooter=1,$showonlymess if ($printfooter && function_exists("llxFooter")) llxFooter(); exit(0); } - diff --git a/htdocs/core/login/functions_dolibarr.php b/htdocs/core/login/functions_dolibarr.php index d8cf78747b8..25d5f2dc30c 100644 --- a/htdocs/core/login/functions_dolibarr.php +++ b/htdocs/core/login/functions_dolibarr.php @@ -84,7 +84,7 @@ function check_user_password_dolibarr($usertotest,$passwordtotest,$entitytotest= // Check crypted password according to crypt algorithm if ($cryptType == 'md5') { - if (dol_hash($passtyped) == $passcrypted) + if (dol_verifyHash($passtyped, $passcrypted)) { $passok=true; dol_syslog("functions_dolibarr::check_user_password_dolibarr Authentification ok - ".$cryptType." of pass is ok"); @@ -152,5 +152,3 @@ function check_user_password_dolibarr($usertotest,$passwordtotest,$entitytotest= return $login; } - - diff --git a/htdocs/install/step5.php b/htdocs/install/step5.php index 8a39faf526a..d271e552dd0 100644 --- a/htdocs/install/step5.php +++ b/htdocs/install/step5.php @@ -181,7 +181,7 @@ if ($action == "set" || empty($action) || preg_match('/upgrade/i',$action)) // Define default setup for password encryption dolibarr_set_const($db, "DATABASE_PWD_ENCRYPTED", "1", 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_SECURITY_SALT", dol_print_date(dol_now(), 'dayhourlog'), 'chaine', 0, '', 0); // All entities - dolibarr_set_const($db, "MAIN_SECURITY_HASH_ALGO", 'sha1md5', 'chaine', 0, '', 0); // All entities + dolibarr_set_const($db, "MAIN_SECURITY_HASH_ALGO", 'password_hash', 'chaine', 0, '', 0); // All entities } } diff --git a/htdocs/user/passwordforgotten.php b/htdocs/user/passwordforgotten.php index 4412eb621b3..9bc2b57f202 100644 --- a/htdocs/user/passwordforgotten.php +++ b/htdocs/user/passwordforgotten.php @@ -78,7 +78,7 @@ if ($action == 'validatenewpassword' && $username && $passwordhash) } else { - if (dol_hash($edituser->pass_temp) == $passwordhash) + if (dol_verifyHash($edituser->pass_temp, $passwordhash)) { $newpassword=$edituser->setPassword($user,$edituser->pass_temp,0); dol_syslog("passwordforgotten.php new password for user->id=".$edituser->id." validated in database"); @@ -238,4 +238,3 @@ $reshook = $hookmanager->executeHooks('getPasswordForgottenPageExtraOptions',$pa $moreloginextracontent = $hookmanager->resPrint; include $template_dir.'passwordforgotten.tpl.php'; // To use native PHP - From b86a5d56233d49a2af8d40435d8a0994bdadc790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Labate?= Date: Mon, 15 Jan 2018 11:02:08 +0100 Subject: [PATCH 2/2] FIX add password_hash compatibility test for PHP < 5.5 --- htdocs/core/lib/security.lib.php | 5 +++-- htdocs/install/step5.php | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php index 88e6ebb7af5..ed757a16765 100644 --- a/htdocs/core/lib/security.lib.php +++ b/htdocs/core/lib/security.lib.php @@ -82,7 +82,8 @@ function dol_hash($chain, $type='0') global $conf; // No need to add salt for password_hash - if ($type == '0' && ! empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash') return password_hash($chain, PASSWORD_DEFAULT); + if ($type == '0' && ! empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash' && function_exists('password_hash')) + return password_hash($chain, PASSWORD_DEFAULT); // Salt value if (! empty($conf->global->MAIN_SECURITY_SALT)) $chain=$conf->global->MAIN_SECURITY_SALT.$chain; @@ -114,7 +115,7 @@ function dol_verifyHash($chain, $hash, $type='0') { global $conf; - if ($type == '0' && ! empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash') { + if ($type == '0' && ! empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash' && function_exists('password_verify')) { if ($hash[0] == '$') return password_verify($chain, $hash); else if(strlen($hash) == 32) return dol_verifyHash($chain, $hash, '3'); // md5 else if(strlen($hash) == 40) return dol_verifyHash($chain, $hash, '2'); // sha1md5 diff --git a/htdocs/install/step5.php b/htdocs/install/step5.php index d271e552dd0..91c517f9644 100644 --- a/htdocs/install/step5.php +++ b/htdocs/install/step5.php @@ -181,7 +181,10 @@ if ($action == "set" || empty($action) || preg_match('/upgrade/i',$action)) // Define default setup for password encryption dolibarr_set_const($db, "DATABASE_PWD_ENCRYPTED", "1", 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_SECURITY_SALT", dol_print_date(dol_now(), 'dayhourlog'), 'chaine', 0, '', 0); // All entities - dolibarr_set_const($db, "MAIN_SECURITY_HASH_ALGO", 'password_hash', 'chaine', 0, '', 0); // All entities + if (function_exists('password_hash')) + dolibarr_set_const($db, "MAIN_SECURITY_HASH_ALGO", 'password_hash', 'chaine', 0, '', 0); // All entities + else + dolibarr_set_const($db, "MAIN_SECURITY_HASH_ALGO", 'sha1md5', 'chaine', 0, '', 0); // All entities } }