From 858d3386b75d430d8cad839f59bacc46ebca420a Mon Sep 17 00:00:00 2001 From: Jesse Norell <jesse@kci.net> Date: Tue, 1 Feb 2022 16:58:39 -0700 Subject: [PATCH] more secure unique strings --- .../autoinstall.conf_sample.php | 4 +- install/dist/conf/centos80.conf.php | 4 +- install/dist/conf/debian100.conf.php | 4 +- install/dist/conf/debian110.conf.php | 4 +- install/dist/conf/debian90.conf.php | 4 +- install/dist/conf/debiantesting.conf.php | 4 +- install/dist/conf/gentoo.conf.php | 4 +- install/dist/conf/ubuntu1604.conf.php | 4 +- install/dist/conf/ubuntu1710.conf.php | 4 +- install/dist/conf/ubuntu1804.conf.php | 4 +- install/dist/conf/ubuntu2004.conf.php | 4 +- install/lib/installer_base.lib.php | 1 + interface/lib/app.inc.php | 2 + interface/lib/classes/auth.inc.php | 18 ++--- interface/lib/classes/functions.inc.php | 18 ++--- interface/lib/classes/remoting.inc.php | 4 +- interface/lib/compatibility.inc.php | 80 +++++++++++++++++++ interface/web/login/password_reset.php | 2 +- server/lib/classes/functions.inc.php | 6 +- server/lib/classes/letsencrypt.inc.php | 2 +- .../plugins-available/apache2_plugin.inc.php | 11 +-- server/plugins-available/nginx_plugin.inc.php | 12 +-- 22 files changed, 136 insertions(+), 64 deletions(-) create mode 100644 interface/lib/compatibility.inc.php diff --git a/docs/autoinstall_samples/autoinstall.conf_sample.php b/docs/autoinstall_samples/autoinstall.conf_sample.php index 904d65403c..c8bf209f9f 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 0411fb9ce5..36e85e02d2 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 0861af83de..b6b0dc4135 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 c60152df5c..10f57d88a1 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 e5d1d8a9b4..b253a31f22 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 cbc380fffb..3a06dfb86b 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 24c7d0633e..23558a164d 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 0d3fe23bad..bd8d0bcd1c 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 0730f8f2d5..d365388549 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 2a09f787db..fa96f7a5ca 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 fe5a9b083b..28d4bf3c14 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 103abaef19..3a3d415bb5 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 ee4713cd98..7ff158fbdc 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 a69d43da2e..3a4cc1603c 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 02d573a778..98cdc71a4f 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 '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,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 = ?", @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->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->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 80e30bf849..23c123ec6c 100644 --- a/interface/lib/classes/remoting.inc.php +++ b/interface/lib/classes/remoting.inc.php @@ -139,7 +139,7 @@ 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)); + $remote_session = bin2hex(random_bytes(20)); $remote_userid = $user['userid']; $remote_functions = ''; $tstamp = time() + $this->session_timeout; @@ -211,7 +211,7 @@ 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)); + $remote_session = 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/compatibility.inc.php b/interface/lib/compatibility.inc.php new file mode 100644 index 0000000000..562e07ada4 --- /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 db4ad71c22..659075483c 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 5296c3012b..34e5943cda 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 ac805a6b67..c9f22f14c5 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 f2a121825b..35133ae322 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 0e2cacaef9..9e111e72d9 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 -- GitLab