Как создать хорошую соль. Является ли моя функция достаточно надежной?

Вот функция, которую я использую для создания случайных солей:

function generateRandomString($nbLetters){ $randString=""; $charUniverse="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; for($i=0; $i<$nbLetters; $i++){ $randInt=rand(0,61); $randChar=$charUniverse[$randInt]; $randString=$randomString.$randChar; } return $randomString; } 

Это для некоммерческого веб-сайта. Он используется только для создания соли (для хранения в db и используется вместе с пользователем, представленным pw для хэширования).

Это уместно? Должен ли я использовать большее подмножество символов, и если так, то есть простой способ сделать это в PHP?

На странице php sha1 :

 $salt = uniqid(mt_rand(), true); 

Это выглядит проще и эффективнее (поскольку каждый из них уникален), чем то, что вы предложили.

Если вы работаете в Linux, /dev/urandom , вероятно, ваш лучший источник случайности. Он поставляется самой ОС, поэтому он гарантированно будет намного более надежным, чем любая встроенная функция PHP.

 $fp = fopen('/dev/urandom', 'r'); $randomString = fread($fp, 32); fclose($fp); 

Это даст вам 32 байта случайного blob. Вы, вероятно, захотите передать это через что-то вроде base64_encode() чтобы сделать его разборчивым. Не нужно самостоятельно манипулировать символами.

Изменить 2014: В PHP 5.3 и выше openssl_random_pseudo_bytes() – это самый простой способ получить кучу случайных байтов. В системах * nix он использует /dev/urandom за кулисами. В системах Windows он использует другой алгоритм, встроенный в библиотеку OpenSSL.

Связано: https://security.stackexchange.com/questions/26206

Связано: следует ли использовать urandom или openssl_random_pseudo_bytes?

password_hash() доступен в PHP 5.5 и новее. Я удивлен, узнав, что здесь не упоминается.

С password_hash () нет необходимости генерировать соль, поскольку соль автоматически генерируется с использованием алгоритма bcrypt – и поэтому не нужно составлять набор символов.

Вместо этого пароль, отправленный пользователем, сравнивается с уникальным хешем пароля, который хранится в базе данных с помощью password_verify (). Просто храните имя пользователя и пароль хэша в таблице базы данных пользователей, после чего вы сможете сравнить его с паролем пользователя, используя пароль_verify ().

Как работает пароль hash ():

Функция password_hash () выводит уникальный хэш пароля при хранении строки в базе данных – рекомендуется, чтобы столбец допускал до 255 символов.

 $password = "goat"; echo password_hash($password, PASSWORD_DEFAULT); echo password_hash($password, PASSWORD_DEFAULT); echo password_hash($password, PASSWORD_DEFAULT); // Output example (store this in the database) $2y$10$GBIQaf6gEeU9im8RTKhIgOZ5q5haDA.A5GzocSr5CR.sU8OUsCUwq <- This hash changes. $2y$10$7.y.lLyEHKfpxTRnT4HmweDKWojTLo1Ra0hXXlAC4ra1pfneAbj0K $2y$10$5m8sFNEpJLBfMt/3A0BI5uH4CKep2hiNI1/BnDIG0PpLXpQzIHG8y 

Чтобы проверить хешированный пароль, вы используете password_verify() :

 $password_enc = password_hash("goat", PASSWORD_DEFAULT); dump(password_verify('goat', $password_enc)); // TRUE dump(password_verify('fish', $password_enc)); // FALSE 

Если вы предпочитаете, соль можно добавить вручную в качестве опции, например:

 $password = 'MyPassword'; $salt = 'MySaltThatUsesALongAndImpossibleToRememberSentence+NumbersSuch@7913'; $hash = password_hash($password, PASSWORD_DEFAULT, ['salt'=>$salt]); // Output: $2y$10$TXlTYWx0VGhhdFVzZXNBT.ApoIjIiwyhEvKC9Ok5qzVcSal7T8CTu <- This password hash not change. 

Замените rand(0,61) на mt_rand(0, 61) и вы должны быть в порядке (так как mt_rand лучше производит случайные числа) …

Но более важным, чем сила соли, является то, как вы это делаете. Если у вас отличная соль, но только md5($pass.$salt) , вы выбрасываете соль. Я лично рекомендую растягивать хэш … Например:

 function getSaltedHash($password, $salt) { $hash = $password . $salt; for ($i = 0; $i < 50; $i++) { $hash = hash('sha512', $password . $hash . $salt); } return $hash; } 

Для получения дополнительной информации о растягивании хэшей, проверьте этот ответ SO …

Я хотел бы получить совет от другого ответа и использовать mt_rand (0, 61) , потому что Mersenne Twister производит лучшую энтропию.

Кроме того, ваша функция на самом деле состоит из двух частей: генерации случайных чисел $nbLetters и кодирования в base62. Это упростит работу программиста по обслуживанию (возможно, вы!), Который через несколько лет пробирается через него:

 // In a class somewhere private $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; private function getBase62Char($num) { return $chars[$num]; } public function generateRandomString($nbLetters){ $randString=""; for($i=0; $i < $nbLetters; $i++){ $randChar = getBase62Char(mt_rand(0,61)); $randString .= $randChar; } return $randomString; } 

Я думаю, что очень хорошей солью является имя пользователя (если вы говорите о хэшировании pw и имя пользователя не изменяется).

Вам не нужно ничего генерировать и не нужно хранить дополнительные данные.

Достаточно простая методика:

 $a = array('a', 'b', ...., 'A', 'B', ..., '9'); shuffle($a); $salt = substr(implode($a), 0, 2); // or whatever sized salt is wanted 

В отличие от uniqid () он генерирует случайный результат.

Я использую это:

 $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM)); 

Это мой метод, он использует по-настоящему случайные числа от атмосферного шума. Все это смешивается с псевдослучайными значениями и строками. Перемешивается и хешируется. Вот мой код: я называю это излишним.

 <?php function generateRandomString($length = 10) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, strlen($characters) - 1)]; } return $randomString; } function get_true_random_number($min = 1, $max = 100) { $max = ((int) $max >= 1) ? (int) $max : 100; $min = ((int) $min < $max) ? (int) $min : 1; $options = array( CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false, CURLOPT_FOLLOWLOCATION => true, CURLOPT_ENCODING => '', CURLOPT_USERAGENT => 'PHP', CURLOPT_AUTOREFERER => true, CURLOPT_CONNECTTIMEOUT => 120, CURLOPT_TIMEOUT => 120, CURLOPT_MAXREDIRS => 10, ); $ch = curl_init('http://www.random.org/integers/?num=1&min=' . $min . '&max=' . $max . '&col=1&base=10&format=plain&rnd=new'); curl_setopt_array($ch, $options); $content = curl_exec($ch); curl_close($ch); if(is_numeric($content)) { return trim($content); } else { return rand(-10,127); } } function generateSalt() { $string = generateRandomString(10); $int = get_true_random_number(-2,123); $shuffled_mixture = str_shuffle(Time().$int.$string); return $salt = md5($shuffled_mixture); } echo generateSalt(); ?> 

Атмосферный шум предоставляется random.org. Я также видел по-настоящему случайное поколение изображений лавовых ламп, которые интерпретируются через оттенок и местоположение. (Hue – это местоположение)

Вот гораздо лучший способ, если у вас есть окна и can not do / dev / random.

 //Key generator $salt = base64_encode(openssl_random_pseudo_bytes(128, $secure)); //The variable $secure is given by openssl_random_ps... and it will give a true or false if its tru then it means that the salt is secure for cryptologic. while(!$secure){ $salt = base64_encode(openssl_random_pseudo_bytes(128, $secure)); } в //Key generator $salt = base64_encode(openssl_random_pseudo_bytes(128, $secure)); //The variable $secure is given by openssl_random_ps... and it will give a true or false if its tru then it means that the salt is secure for cryptologic. while(!$secure){ $salt = base64_encode(openssl_random_pseudo_bytes(128, $secure)); } 

Если вы хотите получить исключительную уникальную соль, вы должны использовать уникальное значение, введенное и требуемое пользователем, например, электронное письмо или имя пользователя, а затем хеширование его с помощью sha1, а затем объединить его – объединить – со значением соли, генерируемым вашим кодом.

Другой, вы должны расширить $charUniverse по средним значениям некоторых специальных символов, таких как @,!#- и т. Д.