Недавно я пытался реализовать свою собственную безопасность в сценарии входа в систему, который я наткнулся на интернет. После попытки попытаться научиться создавать собственный скрипт для создания соли для каждого пользователя, я наткнулся на password_hash.
Из того, что я понимаю (основанный на чтении на этой странице: http://php.net/manual/en/faq.passwords.php), соль уже сгенерирована в строке, когда вы используете password_hash. Это правда?
Еще один вопрос, который у меня был, было бы разумно иметь 2 соли? Один непосредственно в файле и один в БД? Таким образом, если кто-то компрометирует вашу соль в БД, у вас все еще есть один непосредственно в файле? Я читал здесь, что хранение солей никогда не является умной идеей, но это всегда путало меня, что люди подразумевали под этим.
Да, это правда. Почему вы сомневаетесь в php faq для функции? :)
Результат работы password_hash() имеет четыре части:
в алгоритме использованы параметры соль фактический пароль hashИтак, как вы можете видеть, хэш является его частью.
Конечно, у вас может быть дополнительная соль для дополнительного уровня безопасности, но я, честно говоря, считаю, что это слишком много в обычном php-приложении. Алгоритм bcrypt по умолчанию хорош, а опция blowfish, возможно, даже лучше.
Никогда не используйте md5 () для защиты вашего пароля, даже с солью, это всегда опасно !!
Сделайте свой пароль с последними алгоритмами хеширования, как показано ниже.
<?php
// Your original Password
$password = '121@121';
//PASSWORD_BCRYPT or PASSWORD_DEFAULT use any in the 2nd parameter
/*
PASSWORD_BCRYPT always results 60 characters long string.
PASSWORD_DEFAULT capacity is beyond 60 characters
*/
$password_encrypted = password_hash($password, PASSWORD_BCRYPT);
?>
] Для сопоставления с зашифрованным паролем базы данных и введенным пользователем паролем используйте следующую функцию.
<?php
if (password_verify($password_inputted_by_user, $password_encrypted)) {
// Success!
echo 'Password Matches';
}else {
// Invalid credentials
echo 'Password Mismatch';
}
?>
Если вы хотите использовать свою соль, используйте свою собственную созданную функцию для нее, просто следуйте ниже, но я не рекомендую это, поскольку он найден устаревшим в последних версиях PHP.
прочитайте это http://php.net/manual/en/function.password-hash.php перед использованием ниже кода.
<?php
$options = [
'salt' => your_custom_function_for_salt(),
//write your own code to generate a suitable & secured salt
'cost' => 12 // the default cost is 10
];
$hash = password_hash($your_password, PASSWORD_DEFAULT, $options);
?>
Надеюсь, что все это поможет !!
Да, вы поняли это правильно, функция password_hash () будет генерировать соль сама по себе и включает ее в полученное хеш-значение.
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($_POST['password'], PASSWORD_DEFAULT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($_POST['password'], $existingHashFromDb);
Вторая соль, которую вы упомянули (тот, который хранится в файле), на самом деле является перцем или серверной стороной ключ. Если вы добавите его перед хэшированием (например, соль), добавьте перец. Однако есть лучший способ, вы можете сначала вычислить хэш, а затем зашифровать (двухсторонний) хеш с помощью серверного ключа. Это дает вам возможность изменить ключ, когда это необходимо.
В отличие от соли, этот ключ должен храниться в секрете. Люди часто смешивают его и пытаются скрыть соль, но лучше разрешить соль выполнять свою работу и добавить секрет с помощью ключа.
Существует явное отсутствие обсуждения обратной и передовой совместимости, встроенной в функции паролей PHP. Примечательно:
Обратная совместимость. Функции пароля - это, по сути, хорошо написанная оболочка вокруг crypt() и по своей сути обратно совместимы с хешами crypt() -формата, даже если они используют устаревшие и / или небезопасные хэш-алгоритмов. Нападающие Совместимость. Вставка password_needs_rehash() и немного логики в ваш рабочий процесс проверки подлинности может сохранить ваши хешы в актуальном состоянии с текущими и будущими алгоритмами с потенциально нулевыми будущими изменениями рабочего процесса. Примечание. Любая строка, которая не соответствует указанному алгоритму, будет помечена для необходимости повторного использования, включая хэши, не совместимые с криптографическим кодом.Например:
class FakeDB {
public function __call($name, $args) {
printf("%s::%s(%s)\n", __CLASS__, $name, json_encode($args));
return $this;
}
}
class MyAuth {
protected $dbh;
protected $fakeUsers = [
// old crypt-md5 format
1 => ['password' => '$1$AVbfJOzY$oIHHCHlD76Aw1xmjfTpm5.'],
// old salted md5 format
2 => ['password' => '3858f62230ac3c915f300c664312c63f', 'salt' => 'bar'],
// current bcrypt format
3 => ['password' => '$2y$10$3eUn9Rnf04DR.aj8R3WbHuBO9EdoceH9uKf6vMiD7tz766rMNOyTO']
];
public function __construct($dbh) {
$this->dbh = $dbh;
}
protected function getuser($id) {
// just pretend these are coming from the DB
return $this->fakeUsers[$id];
}
public function authUser($id, $password) {
$userInfo = $this->getUser($id);
// Do you have old, turbo-legacy, non-crypt hashes?
if( strpos( $userInfo['password'], '$' ) !== 0 ) {
printf("%s::legacy_hash\n", __METHOD__);
$res = $userInfo['password'] === md5($password . $userInfo['salt']);
} else {
printf("%s::password_verify\n", __METHOD__);
$res = password_verify($password, $userInfo['password']);
}
// once we've passed validation we can check if the hash needs updating.
if( $res && password_needs_rehash($userInfo['password'], PASSWORD_DEFAULT) ) {
printf("%s::rehash\n", __METHOD__);
$stmt = $this->dbh->prepare('UPDATE users SET pass = ? WHERE user_id = ?');
$stmt->execute([password_hash($password, PASSWORD_DEFAULT), $id]);
}
return $res;
}
}
$auth = new MyAuth(new FakeDB());
for( $i=1; $i<=3; $i++) {
var_dump($auth->authuser($i, 'foo'));
echo PHP_EOL;
}
Выход:
MyAuth::authUser::password_verify
MyAuth::authUser::rehash
FakeDB::prepare(["UPDATE users SET pass = ? WHERE user_id = ?"])
FakeDB::execute([["$2y$10$zNjPwqQX\/RxjHiwkeUEzwOpkucNw49yN4jjiRY70viZpAx5x69kv.",1]])
bool(true)
MyAuth::authUser::legacy_hash
MyAuth::authUser::rehash
FakeDB::prepare(["UPDATE users SET pass = ? WHERE user_id = ?"])
FakeDB::execute([["$2y$10$VRTu4pgIkGUvilTDRTXYeOQSEYqe2GjsPoWvDUeYdV2x\/\/StjZYHu",2]])
bool(true)
MyAuth::authUser::password_verify
bool(true)
В качестве последней заметки, учитывая, что вы можете только повторно использовать пароль пользователя при входе в систему, вы следует учитывать «заходящие» ненадежные устаревшие хэши для защиты ваших пользователей. Под этим я подразумеваю, что после определенного льготного периода вы удаляете все неустойчивые [например: голые MD5 / SHA / в противном случае слабые] хэши и ваши пользователи полагаются на механизмы сброса пароля вашего приложения.
Я создал функцию, которую я все время использую для проверки пароля и создания паролей, например. для их хранения в базе данных MySQL. Он использует случайно сгенерированную соль, которая более безопасна, чем использование статической соли.
function secure_password($user_pwd, $multi) {
/*
secure_password ( string $user_pwd, boolean/string $multi )
*** Description:
This function verifies a password against a (database-) stored password's hash or
returns $hash for a given password if $multi is set to either true or false
*** Examples:
// To check a password against its hash
if(secure_password($user_password, $row['user_password'])) {
login_function();
}
// To create a password-hash
$my_password = 'uber_sEcUrE_pass';
$hash = secure_password($my_password, true);
echo $hash;
*/
// Set options for encryption and build unique random hash
$crypt_options = ['cost' => 11, 'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM)];
$hash = password_hash($user_pwd, PASSWORD_BCRYPT, $crypt_options);
// If $multi is not boolean check password and return validation state true/false
if($multi!==true && $multi!==false) {
if (password_verify($user_pwd, $table_pwd = $multi)) {
return true; // valid password
} else {
return false; // invalid password
}
// If $multi is boolean return $hash
} else return $hash;
}