CVE-2021-3990: Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG) (CWE-338)
value: showdoc is vulnerable to Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)
CWE description: The product uses a Pseudo-Random Number Generator (PRNG) in a security context, but the PRNG's algorithm is not cryptographically strong.
CVSS v3 base score: 6.5
Published: 2021-12-01T11:15Z
Repository: https://github.com/star7th/showdoc
Language: PHP
Files changed: server/Application/Api/Controller/AdminSettingController.class.php, server/Application/Api/Model/UserModel.class.php, server/Application/Common/Common/function.php
Commit date: 2021-11-20 20:58:35 +0800
Commit message: Enhanced LDAP user password / 增强ldap用户密码

Diff: diff --git a/server/Application/Api/Controller/AdminSettingController.class.php b/server/Application/Api/Controller/AdminSettingController.class.php
index b236ac4a..0db78c03 100644
--- a/server/Application/Api/Controller/AdminSettingController.class.php
+++ b/server/Application/Api/Controller/AdminSettingController.class.php
@@ -98,11 +98,11 @@ class AdminSettingController extends BaseController {
                 if (!$ldap_user) {
                     continue ;
                 }
                 //如果该用户不在数据库里，则帮助其注册
                 if(!D("User")->isExist($ldap_user)){
-                    D("User")->register($ldap_user,$ldap_user.time());
+                    D("User")->register($ldap_user,$ldap_user.get_rand_str());
                 }
             }
             D("Options")->set("ldap_form" , json_encode( $ldap_form)) ;
         }
         D("Options")->set("ldap_open" ,$ldap_open) ;
@@ -219,11 +219,11 @@ class AdminSettingController extends BaseController {
                 $dn = $data[$i]["dn"] ;
                 if ($ldap_user == $username) {
                     //如果该用户不在数据库里，则帮助其注册
                     $userInfo = D("User")->isExist($username) ;
                     if(!$userInfo){
-                        D("User")->register($ldap_user,$ldap_user.time());
+                        D("User")->register($ldap_user,$ldap_user.get_rand_str());
                     }
                     $rs2=ldap_bind($ldap_conn, $dn , $password);
                     if ($rs2) {
                        D("User")->updatePwd($userInfo['uid'], $password);
                        $this->sendResult(array());
diff --git a/server/Application/Api/Model/UserModel.class.php b/server/Application/Api/Model/UserModel.class.php
index c19591b0..0c881139 100644
--- a/server/Application/Api/Model/UserModel.class.php
+++ b/server/Application/Api/Model/UserModel.class.php
@@ -90,11 +90,11 @@ class UserModel extends BaseModel {
                 $dn = $data[$i]["dn"] ;
                 if ($ldap_user == $username) {
                     //如果该用户不在数据库里，则帮助其注册
                     $userInfo = D("User")->isExist($username) ;
                     if(!$userInfo){
-                        D("User")->register($ldap_user,$ldap_user.time());
+                        D("User")->register($ldap_user,$ldap_user.get_rand_str());
                     }
                     $rs2=ldap_bind($ldap_conn, $dn , $password);
                     if ($rs2) {
                        D("User")->updatePwd($userInfo['uid'], $password);
                        return $this->checkLogin($username,$password);
diff --git a/server/Application/Common/Common/function.php b/server/Application/Common/Common/function.php
index 2d7c4eb2..0fb64f3a 100644
--- a/server/Application/Common/Common/function.php
+++ b/server/Application/Common/Common/function.php
@@ -210,6 +210,23 @@ function uncompress_string($string){
 
 //获取环境变量。如果环境变量不存在，将返回第一个参数
 function env($name , $default_value = false){
     return getenv($name) ? getenv($name) : $default_value ;
 
+}
+
+// 获取随机字符串
+function get_rand_str($len = 32 ){
+    // 对于php7以上版本，可利用random_bytes产生随机
+    if(version_compare(PHP_VERSION,'7.0','>')){
+        $rand = bin2hex( random_bytes( 16 ) ); 
+        return substr($rand,0,$len); 
+    }else{
+        // 对于低版本，只好尽量加大长度实现伪随机，增大暴力破解难度
+        $s1 = microtime(true).time().rand().rand().rand().microtime(true).time().rand().rand().rand();
+        $s2 = microtime(true).time().rand().rand().rand().microtime(true).time().rand().rand().rand();
+        $md5 = md5($s2.base64_encode($s1));
+        return substr($md5,0,$len);
+    }
+
+    
 }
\ No newline at end of file

Vulnerable code:                     D("User")->register($ldap_user,$ldap_user.time());
                        D("User")->register($ldap_user,$ldap_user.time());
                        D("User")->register($ldap_user,$ldap_user.time());
Fixed code:                     D("User")->register($ldap_user,$ldap_user.get_rand_str());
                        D("User")->register($ldap_user,$ldap_user.get_rand_str());
                        D("User")->register($ldap_user,$ldap_user.get_rand_str());
}

// 获取随机字符串
function get_rand_str($len = 32 ){
    // 对于php7以上版本，可利用random_bytes产生随机
    if(version_compare(PHP_VERSION,'7.0','>')){
        $rand = bin2hex( random_bytes( 16 ) ); 
        return substr($rand,0,$len); 
    }else{
        // 对于低版本，只好尽量加大长度实现伪随机，增大暴力破解难度
        $s1 = microtime(true).time().rand().rand().rand().microtime(true).time().rand().rand().rand();
        $s2 = microtime(true).time().rand().rand().rand().microtime(true).time().rand().rand().rand();
        $md5 = md5($s2.base64_encode($s1));
        return substr($md5,0,$len);
    }