Ответ 1
На странице php sha1:
$salt = uniqid(mt_rand(), true);
Это выглядит проще и эффективнее (поскольку каждый из них уникален), чем вы предложили.
Здесь функция, которую я использую для генерации случайных солей:
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 = '[email protected]913';
$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));
}
Если вы хотите получить уникальную соль, вы должны использовать уникальное значение, введенное и требуемое пользователем, например, электронное письмо или имя пользователя, а затем хэшировать его с помощью sha1, а затем объединить его - объединить - со значением соли, генерируемым вашим кодом.
Другой, вы должны расширить $charUniverse
средним значением некоторых специальных символов, таких как @,!#-
и т.д.