diff --git a/docs/autoinstall_samples/autoinstall.conf_sample.php b/docs/autoinstall_samples/autoinstall.conf_sample.php
index 904d65403cb40c4060094c813dcc2eae4f121803..c8bf209f9fcb2d9284f2fed8b33f96091ec36496 100644
--- a/docs/autoinstall_samples/autoinstall.conf_sample.php
+++ b/docs/autoinstall_samples/autoinstall.conf_sample.php
@@ -29,7 +29,7 @@ $autoinstall['ssl_cert_email'] = 'hostmaster@'.$autoinstall['hostname'];
 
 /* optional expert mode settings, needed only for expert mode */
 $autoinstall['mysql_ispconfig_user'] = 'ispconfig'; // default: ispconfig
-$autoinstall['mysql_ispconfig_password'] = md5(uniqid(rand()));
+$autoinstall['mysql_ispconfig_password'] = bin2hex(random_bytes(20));
 $autoinstall['join_multiserver_setup'] = 'n'; // y, n (default)
 $autoinstall['mysql_master_hostname'] = 'master.example.com';
 $autoinstall['mysql_master_root_user'] = 'root';
@@ -70,4 +70,4 @@ $autoupdate['svc_detect_change_firewall_server'] = 'yes'; // yes (default), no
 $autoupdate['svc_detect_change_vserver_server'] = 'yes'; // yes (default), no
 $autoupdate['svc_detect_change_db_server'] = 'yes'; // yes (default), no
 
-?>
\ No newline at end of file
+?>
diff --git a/install/dist/conf/centos80.conf.php b/install/dist/conf/centos80.conf.php
index 0411fb9ce5e95238cf29c0cf1afb374cd5458209..36e85e02d2448f6e9dba8a216eaa3561d46478cb 100644
--- a/install/dist/conf/centos80.conf.php
+++ b/install/dist/conf/centos80.conf.php
@@ -63,14 +63,14 @@ $conf['mysql']['admin_user'] = 'root';
 $conf['mysql']['admin_password'] = '';
 $conf['mysql']['charset'] = 'utf8';
 $conf['mysql']['ispconfig_user'] = 'ispconfig';
-$conf['mysql']['ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['ispconfig_password'] = md5(random_bytes(20));
 $conf['mysql']['master_slave_setup'] = 'n';
 $conf['mysql']['master_host'] = '';
 $conf['mysql']['master_database'] = 'dbispconfig';
 $conf['mysql']['master_admin_user'] = 'root';
 $conf['mysql']['master_admin_password'] = '';
 $conf['mysql']['master_ispconfig_user'] = '';
-$conf['mysql']['master_ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['master_ispconfig_password'] = md5(random_bytes(20));
 
 //* Apache
 $conf['apache']['installed'] = false; // will be detected automatically during installation
diff --git a/install/dist/conf/debian100.conf.php b/install/dist/conf/debian100.conf.php
index 0861af83deb1729230d9d978e0cdd38b0d0371d4..b6b0dc4135156e154a58c0793d53b4d2475b1f1d 100644
--- a/install/dist/conf/debian100.conf.php
+++ b/install/dist/conf/debian100.conf.php
@@ -65,14 +65,14 @@ $conf['mysql']['admin_user'] = 'root';
 $conf['mysql']['admin_password'] = '';
 $conf['mysql']['charset'] = 'utf8';
 $conf['mysql']['ispconfig_user'] = 'ispconfig';
-$conf['mysql']['ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['ispconfig_password'] = md5(random_bytes(20));
 $conf['mysql']['master_slave_setup'] = 'n';
 $conf['mysql']['master_host'] = '';
 $conf['mysql']['master_database'] = 'dbispconfig';
 $conf['mysql']['master_admin_user'] = 'root';
 $conf['mysql']['master_admin_password'] = '';
 $conf['mysql']['master_ispconfig_user'] = '';
-$conf['mysql']['master_ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['master_ispconfig_password'] = md5(random_bytes(20));
 
 //* Apache
 $conf['apache']['installed'] = false; // will be detected automatically during installation
diff --git a/install/dist/conf/debian110.conf.php b/install/dist/conf/debian110.conf.php
index c60152df5c846daa79feaa03868cc65236f0e32a..10f57d88a1f04af767c4b783a14095360c831b2c 100644
--- a/install/dist/conf/debian110.conf.php
+++ b/install/dist/conf/debian110.conf.php
@@ -65,14 +65,14 @@ $conf['mysql']['admin_user'] = 'root';
 $conf['mysql']['admin_password'] = '';
 $conf['mysql']['charset'] = 'utf8';
 $conf['mysql']['ispconfig_user'] = 'ispconfig';
-$conf['mysql']['ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['ispconfig_password'] = md5(random_bytes(20));
 $conf['mysql']['master_slave_setup'] = 'n';
 $conf['mysql']['master_host'] = '';
 $conf['mysql']['master_database'] = 'dbispconfig';
 $conf['mysql']['master_admin_user'] = 'root';
 $conf['mysql']['master_admin_password'] = '';
 $conf['mysql']['master_ispconfig_user'] = '';
-$conf['mysql']['master_ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['master_ispconfig_password'] = md5(random_bytes(20));
 
 //* Apache
 $conf['apache']['installed'] = false; // will be detected automatically during installation
diff --git a/install/dist/conf/debian90.conf.php b/install/dist/conf/debian90.conf.php
index e5d1d8a9b4f43c767ee5520b3cb61ce9d6f29424..b253a31f227c67e02c38e7289f70bb17a168cfa8 100644
--- a/install/dist/conf/debian90.conf.php
+++ b/install/dist/conf/debian90.conf.php
@@ -65,14 +65,14 @@ $conf['mysql']['admin_user'] = 'root';
 $conf['mysql']['admin_password'] = '';
 $conf['mysql']['charset'] = 'utf8';
 $conf['mysql']['ispconfig_user'] = 'ispconfig';
-$conf['mysql']['ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['ispconfig_password'] = md5(random_bytes(20));
 $conf['mysql']['master_slave_setup'] = 'n';
 $conf['mysql']['master_host'] = '';
 $conf['mysql']['master_database'] = 'dbispconfig';
 $conf['mysql']['master_admin_user'] = 'root';
 $conf['mysql']['master_admin_password'] = '';
 $conf['mysql']['master_ispconfig_user'] = '';
-$conf['mysql']['master_ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['master_ispconfig_password'] = md5(random_bytes(20));
 
 //* Apache
 $conf['apache']['installed'] = false; // will be detected automatically during installation
diff --git a/install/dist/conf/debiantesting.conf.php b/install/dist/conf/debiantesting.conf.php
index cbc380fffb931252aba4593aad1a8376a0b4d84a..3a06dfb86b5f2a310dcebe0b56469e295002dd6c 100644
--- a/install/dist/conf/debiantesting.conf.php
+++ b/install/dist/conf/debiantesting.conf.php
@@ -65,14 +65,14 @@ $conf['mysql']['admin_user'] = 'root';
 $conf['mysql']['admin_password'] = '';
 $conf['mysql']['charset'] = 'utf8';
 $conf['mysql']['ispconfig_user'] = 'ispconfig';
-$conf['mysql']['ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['ispconfig_password'] = md5(random_bytes(20));
 $conf['mysql']['master_slave_setup'] = 'n';
 $conf['mysql']['master_host'] = '';
 $conf['mysql']['master_database'] = 'dbispconfig';
 $conf['mysql']['master_admin_user'] = 'root';
 $conf['mysql']['master_admin_password'] = '';
 $conf['mysql']['master_ispconfig_user'] = '';
-$conf['mysql']['master_ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['master_ispconfig_password'] = md5(random_bytes(20));
 
 //* Apache
 $conf['apache']['installed'] = false; // will be detected automatically during installation
diff --git a/install/dist/conf/gentoo.conf.php b/install/dist/conf/gentoo.conf.php
index 24c7d0633e0b5b62db4004f329e83d503fb66aad..23558a164d7f11a2bea85d20833052481da06a85 100644
--- a/install/dist/conf/gentoo.conf.php
+++ b/install/dist/conf/gentoo.conf.php
@@ -63,14 +63,14 @@ $conf['mysql']['admin_user'] = 'root';
 $conf['mysql']['admin_password'] = '';
 $conf['mysql']['charset'] = 'utf8';
 $conf['mysql']['ispconfig_user'] = 'ispconfig';
-$conf['mysql']['ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['ispconfig_password'] = md5(random_bytes(20));
 $conf['mysql']['master_slave_setup'] = 'n';
 $conf['mysql']['master_host'] = '';
 $conf['mysql']['master_database'] = 'dbispconfig';
 $conf['mysql']['master_admin_user'] = 'root';
 $conf['mysql']['master_admin_password'] = '';
 $conf['mysql']['master_ispconfig_user'] = '';
-$conf['mysql']['master_ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['master_ispconfig_password'] = md5(random_bytes(20));
 
 //* SuPHP
 $conf['suphp']['config_file'] = '/etc/suphp.conf';
diff --git a/install/dist/conf/ubuntu1604.conf.php b/install/dist/conf/ubuntu1604.conf.php
index 0d3fe23bada198df3c9aae42b6cb42784973a6c1..bd8d0bcd1cbb794cbd1ea39cdb4591328517738b 100644
--- a/install/dist/conf/ubuntu1604.conf.php
+++ b/install/dist/conf/ubuntu1604.conf.php
@@ -65,14 +65,14 @@ $conf['mysql']['admin_user'] = 'root';
 $conf['mysql']['admin_password'] = '';
 $conf['mysql']['charset'] = 'utf8';
 $conf['mysql']['ispconfig_user'] = 'ispconfig';
-$conf['mysql']['ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['ispconfig_password'] = md5(random_bytes(20));
 $conf['mysql']['master_slave_setup'] = 'n';
 $conf['mysql']['master_host'] = '';
 $conf['mysql']['master_database'] = 'dbispconfig';
 $conf['mysql']['master_admin_user'] = 'root';
 $conf['mysql']['master_admin_password'] = '';
 $conf['mysql']['master_ispconfig_user'] = '';
-$conf['mysql']['master_ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['master_ispconfig_password'] = md5(random_bytes(20));
 
 //* Apache
 $conf['apache']['installed'] = false; // will be detected automatically during installation
diff --git a/install/dist/conf/ubuntu1710.conf.php b/install/dist/conf/ubuntu1710.conf.php
index 0730f8f2d533c712ee78173ebb28b3fed477c514..d3653885492dc3d3ae2ded30eef5815ab65065af 100644
--- a/install/dist/conf/ubuntu1710.conf.php
+++ b/install/dist/conf/ubuntu1710.conf.php
@@ -65,14 +65,14 @@ $conf['mysql']['admin_user'] = 'root';
 $conf['mysql']['admin_password'] = '';
 $conf['mysql']['charset'] = 'utf8';
 $conf['mysql']['ispconfig_user'] = 'ispconfig';
-$conf['mysql']['ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['ispconfig_password'] = md5(random_bytes(20));
 $conf['mysql']['master_slave_setup'] = 'n';
 $conf['mysql']['master_host'] = '';
 $conf['mysql']['master_database'] = 'dbispconfig';
 $conf['mysql']['master_admin_user'] = 'root';
 $conf['mysql']['master_admin_password'] = '';
 $conf['mysql']['master_ispconfig_user'] = '';
-$conf['mysql']['master_ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['master_ispconfig_password'] = md5(random_bytes(20));
 
 //* Apache
 $conf['apache']['installed'] = false; // will be detected automatically during installation
diff --git a/install/dist/conf/ubuntu1804.conf.php b/install/dist/conf/ubuntu1804.conf.php
index 2a09f787db46f5abf8fc7d2e15e4804dfe9d3222..fa96f7a5cabf6b691a9d335691744578a699678e 100644
--- a/install/dist/conf/ubuntu1804.conf.php
+++ b/install/dist/conf/ubuntu1804.conf.php
@@ -65,14 +65,14 @@ $conf['mysql']['admin_user'] = 'root';
 $conf['mysql']['admin_password'] = '';
 $conf['mysql']['charset'] = 'utf8';
 $conf['mysql']['ispconfig_user'] = 'ispconfig';
-$conf['mysql']['ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['ispconfig_password'] = md5(random_bytes(20));
 $conf['mysql']['master_slave_setup'] = 'n';
 $conf['mysql']['master_host'] = '';
 $conf['mysql']['master_database'] = 'dbispconfig';
 $conf['mysql']['master_admin_user'] = 'root';
 $conf['mysql']['master_admin_password'] = '';
 $conf['mysql']['master_ispconfig_user'] = '';
-$conf['mysql']['master_ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['master_ispconfig_password'] = md5(random_bytes(20));
 
 //* Apache
 $conf['apache']['installed'] = false; // will be detected automatically during installation
diff --git a/install/dist/conf/ubuntu2004.conf.php b/install/dist/conf/ubuntu2004.conf.php
index fe5a9b083b84db4cd400ef655e9cf5a84170f546..28d4bf3c140e2dad91a04087a0959b2b07f422a5 100644
--- a/install/dist/conf/ubuntu2004.conf.php
+++ b/install/dist/conf/ubuntu2004.conf.php
@@ -65,14 +65,14 @@ $conf['mysql']['admin_user'] = 'root';
 $conf['mysql']['admin_password'] = '';
 $conf['mysql']['charset'] = 'utf8';
 $conf['mysql']['ispconfig_user'] = 'ispconfig';
-$conf['mysql']['ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['ispconfig_password'] = md5(random_bytes(20));
 $conf['mysql']['master_slave_setup'] = 'n';
 $conf['mysql']['master_host'] = '';
 $conf['mysql']['master_database'] = 'dbispconfig';
 $conf['mysql']['master_admin_user'] = 'root';
 $conf['mysql']['master_admin_password'] = '';
 $conf['mysql']['master_ispconfig_user'] = '';
-$conf['mysql']['master_ispconfig_password'] = md5(uniqid(rand()));
+$conf['mysql']['master_ispconfig_password'] = md5(random_bytes(20));
 
 //* Apache
 $conf['apache']['installed'] = false; // will be detected automatically during installation
diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php
index 103abaef1909859b45017bde0f9c6bda9174e7e3..3a3d415bb51c0ab19a5744e442da02d1d7a35210 100644
--- a/install/lib/installer_base.lib.php
+++ b/install/lib/installer_base.lib.php
@@ -190,6 +190,7 @@ class installer_base {
 			$salt_length = 12;
 		}
 
+		// todo: replace the below with password_hash() when we drop php5.4 support
 		if(function_exists('openssl_random_pseudo_bytes')) {
 			$salt .= substr(bin2hex(openssl_random_pseudo_bytes($salt_length)), 0, $salt_length);
 		} else {
diff --git a/interface/lib/app.inc.php b/interface/lib/app.inc.php
index ee4713cd98981ea80e10146d3c1ddedb822ed5a8..7ff158fbdc47a094523a57f86ad95cd901d30547 100755
--- a/interface/lib/app.inc.php
+++ b/interface/lib/app.inc.php
@@ -28,6 +28,8 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+require_once 'compatibility.inc.php';
+
 //* Enable gzip compression for the interface
 ob_start('ob_gzhandler');
 
diff --git a/interface/lib/classes/auth.inc.php b/interface/lib/classes/auth.inc.php
index a69d43da2ec1a079c0d4aefe906684f389d4ffa4..3a4cc1603cca1972f8711c7e09ff19f7c53cc8f9 100644
--- a/interface/lib/classes/auth.inc.php
+++ b/interface/lib/classes/auth.inc.php
@@ -231,7 +231,7 @@ class auth {
 	public function get_random_password($minLength = 8, $special = false) {
 		if($minLength < 8) $minLength = 8;
 		$maxLength = $minLength + 5;
-		$length = mt_rand($minLength, $maxLength);
+		$length = random_int($minLength, $maxLength);
 		
 		$alphachars = "abcdefghijklmnopqrstuvwxyz";
 		$upperchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -240,28 +240,28 @@ class auth {
 		
 		$num_special = 0;
 		if($special == true) {
-			$num_special = intval(mt_rand(0, round($length / 4))) + 1;
+			$num_special = intval(random_int(0, round($length / 4))) + 1;
 		}
-		$numericlen = mt_rand(1, 2);
+		$numericlen = random_int(1, 2);
 		$alphalen = $length - $num_special - $numericlen;
 		$upperlen = intval($alphalen / 2);
 		$alphalen = $alphalen - $upperlen;
 		$password = '';
 		
 		for($i = 0; $i < $alphalen; $i++) {
-			$password .= substr($alphachars, mt_rand(0, strlen($alphachars) - 1), 1);
+			$password .= substr($alphachars, random_int(0, strlen($alphachars) - 1), 1);
 		}
 		
 		for($i = 0; $i < $upperlen; $i++) {
-			$password .= substr($upperchars, mt_rand(0, strlen($upperchars) - 1), 1);
+			$password .= substr($upperchars, random_int(0, strlen($upperchars) - 1), 1);
 		}
 		
 		for($i = 0; $i < $num_special; $i++) {
-			$password .= substr($specialchars, mt_rand(0, strlen($specialchars) - 1), 1);
+			$password .= substr($specialchars, random_int(0, strlen($specialchars) - 1), 1);
 		}
 		
 		for($i = 0; $i < $numericlen; $i++) {
-			$password .= substr($numchars, mt_rand(0, strlen($numchars) - 1), 1);
+			$password .= substr($numchars, random_int(0, strlen($numchars) - 1), 1);
 		}
 		
 		return str_shuffle($password);
@@ -298,8 +298,8 @@ class auth {
 	public function csrf_token_get($form_name) {
 		/* CSRF PROTECTION */
 		// generate csrf protection id and key
-		$_csrf_id = uniqid($form_name . '_'); // form id
-		$_csrf_key = sha1(uniqid(microtime(true), true)); // the key
+		$_csrf_id = $form_name . '_' . bin2hex(random_bytes(12)); // form id
+		$_csrf_key = sha1(random_bytes(20)); // the key
 		if(!isset($_SESSION['_csrf'])) $_SESSION['_csrf'] = array();
 		if(!isset($_SESSION['_csrf_timeout'])) $_SESSION['_csrf_timeout'] = array();
 		$_SESSION['_csrf'][$_csrf_id] = $_csrf_key;
diff --git a/interface/lib/classes/functions.inc.php b/interface/lib/classes/functions.inc.php
index 02d573a77812258d68dbd3716f24f5b2fb85234f..1b396686740bc026b11204d09697debff3cd1a45 100644
--- a/interface/lib/classes/functions.inc.php
+++ b/interface/lib/classes/functions.inc.php
@@ -28,6 +28,8 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+require_once __DIR__.'/../compatibility.inc.php';
+
 //* The purpose of this library is to provide some general functions.
 //* This class is loaded automatically by the ispconfig framework.
 
@@ -437,10 +439,10 @@ class functions {
 		$iteration = 0;
 		$password = "";
 		$maxLength = $minLength + 5;
-		$length = $this->getRandomInt($minLength, $maxLength);
+		$length = random_int($minLength, $maxLength);
 
 		while($iteration < $length){
-			$randomNumber = (floor(((mt_rand() / mt_getrandmax()) * 100)) % 94) + 33;
+			$randomNumber = random_int(33, 126);
 			if(!$special){
 				if (($randomNumber >=33) && ($randomNumber <=47)) { continue; }
 				if (($randomNumber >=58) && ($randomNumber <=64)) { continue; }
@@ -455,10 +457,6 @@ class functions {
 		return $password;
 	}
 
-	public function getRandomInt($min, $max){
-		return floor((mt_rand() / mt_getrandmax()) * ($max - $min + 1)) + $min;
-	}
-
 	public function generate_customer_no(){
 		global $app;
 		// generate customer no.
@@ -474,14 +472,17 @@ class functions {
 		global $app;
 
 		// generate the SSH key pair for the client
-		$id_rsa_file = '/tmp/'.uniqid('',true);
+		if (! $tmpdir = $app->system->exec_safe('mktemp -dt id_rsa.XXXXXXXX')) {
+			$app->log("mktemp failed, cannot create SSH keypair for ".$username, LOGLEVEL_WARN);
+		}
+		$id_rsa_file = $tmpdir . uniqid('',true);
 		$id_rsa_pub_file = $id_rsa_file.'.pub';
 		if(file_exists($id_rsa_file)) unset($id_rsa_file);
 		if(file_exists($id_rsa_pub_file)) unset($id_rsa_pub_file);
 		if(!file_exists($id_rsa_file) && !file_exists($id_rsa_pub_file)) {
 			$app->system->exec_safe('ssh-keygen -t rsa -C ? -f ? -N ""', $username.'-rsa-key-'.time(), $id_rsa_file);
 			$app->db->query("UPDATE client SET created_at = UNIX_TIMESTAMP(), id_rsa = ?, ssh_rsa = ? WHERE client_id = ?", @file_get_contents($id_rsa_file), @file_get_contents($id_rsa_pub_file), $client_id);
-			$app->system->exec_safe('rm -f ? ?', $id_rsa_file, $id_rsa_pub_file);
+			$app->system->rmdir($tmpdir, true);
 		} else {
 			$app->log("Failed to create SSH keypair for ".$username, LOGLEVEL_WARN);
 		}
diff --git a/interface/lib/classes/remoting.inc.php b/interface/lib/classes/remoting.inc.php
index 80e30bf849e203be1fc405ad1a1160a26ed3cc2e..8b888cb231dce17f1741cb09f1a0d04586e47404 100644
--- a/interface/lib/classes/remoting.inc.php
+++ b/interface/lib/classes/remoting.inc.php
@@ -138,8 +138,8 @@ class remoting {
 			}
 
 			//* Create a remote user session
-			//srand ((double)microtime()*1000000);
-			$remote_session = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'),0,1).sha1(mt_rand().uniqid('ispco',true));
+			// session id must begin with a char, not digit, to avoid mysql type confusion abuse
+			$remote_session = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'),0,1).bin2hex(random_bytes(20));
 			$remote_userid = $user['userid'];
 			$remote_functions = '';
 			$tstamp = time() + $this->session_timeout;
@@ -210,8 +210,8 @@ class remoting {
 					return false;
 				}
 				//* Create a remote user session
-				//srand ((double)microtime()*1000000);
-				$remote_session = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'),0,1).sha1(mt_rand().uniqid('ispco',true));
+				// session id must begin with a char, not digit, to avoid mysql type confusion abuse
+				$remote_session = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'),0,1).bin2hex(random_bytes(20));
 				$remote_userid = $remote_user['remote_userid'];
 				$remote_functions = $remote_user['remote_functions'];
 				$tstamp = time() + $this->session_timeout;
diff --git a/interface/lib/classes/system.inc.php b/interface/lib/classes/system.inc.php
index d6b0ef149e285dbe3e3c438cff36bbe44daddac8..9cb171cae5d2f230ede4b117bc1b6900625f1d69 100644
--- a/interface/lib/classes/system.inc.php
+++ b/interface/lib/classes/system.inc.php
@@ -79,6 +79,32 @@ class system {
 		return false;
 	}
 
+	function rmdir($path, $recursive=false) {
+		// Disallow operating on root directory
+		if(realpath($path) == '/') {
+			$app->log("rmdir: afraid I might delete root: $path", LOGLEVEL_WARN);
+			return false;
+		}
+
+		$path = rtrim($path, '/');
+		if (is_dir($path) && !is_link($path)) {
+			$objects = array_diff(scandir($path), array('.', '..'));
+			foreach ($objects as $object) {
+				if ($recursive) {
+					if (is_dir("$path/$object") && !is_link("$path/$object")) {
+						$this->rmdir("$path/$object", $recursive);
+					} else {
+						unlink ("$path/$object");
+					}
+				} else {
+					$app->log("rmdir: invoked non-recursive, not removing $path (expect rmdir failure)", LOGLEVEL_DEBUG);
+				}
+			}
+			return rmdir($path);
+		}
+		return false;
+	}
+
 	public function last_exec_out() {
 		return $this->_last_exec_out;
 	}
diff --git a/interface/lib/compatibility.inc.php b/interface/lib/compatibility.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..562e07ada42f404cae0708f32105dcf39a84768c
--- /dev/null
+++ b/interface/lib/compatibility.inc.php
@@ -0,0 +1,80 @@
+<?php
+
+/*
+Copyright (c) 2021, Jesse Norell <jesse@kci.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of ISPConfig nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* random_bytes can be dropped when php 5.6 support is dropped */
+if (! function_exists('random_bytes')) {
+	function random_bytes($length) {
+		return openssl_random_pseudo_bytes($length);
+	}
+}
+
+/* random_int can be dropped when php 5.6 support is dropped */
+if (! function_exists('random_int')) {
+	function random_int($min=null, $max=null) {
+		if (null === $min) {
+			$min = PHP_INT_MIN;
+		}
+
+		if (null === $max) {
+			$min = PHP_INT_MAX;
+		}
+
+		if (!is_int($min) || !is_int($max)) {
+			trigger_error('random_int: $min and $max must be integer values', E_USER_NOTICE);
+			$min = (int)$min;
+			$max = (int)$max;
+		}
+
+		if ($min > $max) {
+			trigger_error('random_int: $max can\'t be lesser than $min', E_USER_WARNING);
+			return null;
+		}
+
+		$range = $counter = $max - $min;
+		$bits = 1;
+
+		while ($counter >>= 1) {
+			++$bits;
+		}
+
+		$bytes = (int)max(ceil($bits/8), 1);
+		$bitmask = pow(2, $bits) - 1;
+
+		if ($bitmask >= PHP_INT_MAX) {
+			$bitmask = PHP_INT_MAX;
+		}
+
+		do {
+			$result = hexdec(bin2hex(random_bytes($bytes))) & $bitmask;
+		} while ($result > $range);
+
+		return $result + $min;
+	}
+}
diff --git a/interface/web/login/password_reset.php b/interface/web/login/password_reset.php
index db4ad71c22d2614566b0c2658cb4254ee8e7afdb..659075483c918c4813a28e74bf1a67eb8faa7ea9 100644
--- a/interface/web/login/password_reset.php
+++ b/interface/web/login/password_reset.php
@@ -71,7 +71,7 @@ if(isset($_POST['username']) && is_string($_POST['username']) && $_POST['usernam
 	} elseif ($continue) {
 		if($client['client_id'] > 0) {
 			$username = $client['username'];
-			$password_hash = sha1(uniqid('ispc_pw'));
+			$password_hash = sha1(random_bytes(20));
 			$app->db->query("UPDATE sys_user SET lost_password_reqtime = NOW(), lost_password_hash = ? WHERE username = ?", $password_hash, $username);
 
 			$server_domain = (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST']);
diff --git a/server/lib/classes/functions.inc.php b/server/lib/classes/functions.inc.php
index 5296c3012b65cb4bf0d9889c893252e99ec9d4a8..34e5943cda865a11fd279c88dcb57785abf810a4 100644
--- a/server/lib/classes/functions.inc.php
+++ b/server/lib/classes/functions.inc.php
@@ -468,14 +468,16 @@ class functions {
 		global $app;
 
 		// generate the SSH key pair for the client
-		$id_rsa_file = '/tmp/'.uniqid('',true);
+		$app->system->exec_safe('mktemp -dt id_rsa.XXXXXXXX');
+		$tmpdir = $app->system->last_exec_out();
+		$id_rsa_file = $tmpdir . uniqid('',true);
 		$id_rsa_pub_file = $id_rsa_file.'.pub';
 		if(file_exists($id_rsa_file)) unset($id_rsa_file);
 		if(file_exists($id_rsa_pub_file)) unset($id_rsa_pub_file);
 		if(!file_exists($id_rsa_file) && !file_exists($id_rsa_pub_file)) {
 			$app->system->exec_safe('ssh-keygen -t rsa -C ? -f ? -N ""', $username.'-rsa-key-'.time(), $id_rsa_file);
 			$app->db->query("UPDATE client SET created_at = UNIX_TIMESTAMP(), id_rsa = ?, ssh_rsa = ? WHERE client_id = ?", $app->system->file_get_contents($id_rsa_file), $app->system->file_get_contents($id_rsa_pub_file), $client_id);
-			$app->system->exec_safe('rm -f ? ?', $id_rsa_file, $id_rsa_pub_file);
+			$app->system->rmdir($tmpdir, true);
 		} else {
 			$app->log("Failed to create SSH keypair for ".$username, LOGLEVEL_WARN);
 		}
diff --git a/server/lib/classes/letsencrypt.inc.php b/server/lib/classes/letsencrypt.inc.php
index ac805a6b67340506236d995c84dc9c8868adf755..c9f22f14c52d2c97d252cc7f5abb3e20c72f4bee 100644
--- a/server/lib/classes/letsencrypt.inc.php
+++ b/server/lib/classes/letsencrypt.inc.php
@@ -373,7 +373,7 @@ class letsencrypt {
 		$temp_domains = array_unique($temp_domains);
 
 		// check if domains are reachable to avoid letsencrypt verification errors
-		$le_rnd_file = uniqid('le-') . '.txt';
+		$le_rnd_file = uniqid('le-', true) . '.txt';
 		$le_rnd_hash = md5(uniqid('le-', true));
 		if(!is_dir('/usr/local/ispconfig/interface/acme/.well-known/acme-challenge/')) {
 			$app->system->mkdir('/usr/local/ispconfig/interface/acme/.well-known/acme-challenge/', false, 0755, true);
diff --git a/server/plugins-available/apache2_plugin.inc.php b/server/plugins-available/apache2_plugin.inc.php
index f2a121825b75464ee9af81dd935866509b59ee42..35133ae322e4b3a57e239ed2cfe0ecc954233de5 100644
--- a/server/plugins-available/apache2_plugin.inc.php
+++ b/server/plugins-available/apache2_plugin.inc.php
@@ -296,16 +296,9 @@ class apache2_plugin {
 			if(file_exists($crt_file)) $app->system->rename($crt_file, $crt_file.'.bak');
 
 			$rand_file = $ssl_dir.'/random_file';
-			$rand_data = md5(uniqid(microtime(), 1));
-			for($i=0; $i<1000; $i++) {
-				$rand_data .= md5(uniqid(microtime(), 1));
-				$rand_data .= md5(uniqid(microtime(), 1));
-				$rand_data .= md5(uniqid(microtime(), 1));
-				$rand_data .= md5(uniqid(microtime(), 1));
-			}
-			$app->system->file_put_contents($rand_file, $rand_data);
+			$app->system->exec_safe('dd if=/dev/urandom of=? bs=256 count=1', $rand_file);
 
-			$ssl_password = substr(md5(uniqid(microtime(), 1)), 0, 15);
+			$ssl_password = bin2hex(random_bytes(12));
 
 			$ssl_cnf = "        RANDFILE               = $rand_file
 
diff --git a/server/plugins-available/nginx_plugin.inc.php b/server/plugins-available/nginx_plugin.inc.php
index 0e2cacaef9bfd0da4db665ef3cdc3fe68057461f..9e111e72d9e0129563ccad1c610611355af34ca3 100644
--- a/server/plugins-available/nginx_plugin.inc.php
+++ b/server/plugins-available/nginx_plugin.inc.php
@@ -129,16 +129,10 @@ class nginx_plugin {
 			if(file_exists($crt_file)) $app->system->rename($crt_file, $crt_file.'.bak');
 
 			$rand_file = $ssl_dir.'/random_file';
-			$rand_data = md5(uniqid(microtime(), 1));
-			for($i=0; $i<1000; $i++) {
-				$rand_data .= md5(uniqid(microtime(), 1));
-				$rand_data .= md5(uniqid(microtime(), 1));
-				$rand_data .= md5(uniqid(microtime(), 1));
-				$rand_data .= md5(uniqid(microtime(), 1));
-			}
-			$app->system->file_put_contents($rand_file, $rand_data);
+			$app->system->exec_safe('dd if=/dev/urandom of=? bs=256 count=1', $rand_file);
+
+			$ssl_password = bin2hex(random_bytes(12));
 
-			$ssl_password = substr(md5(uniqid(microtime(), 1)), 0, 15);
 
 			$ssl_cnf = "        RANDFILE               = $rand_file