Поэтому я экспериментировал с bcrypt. У меня есть класс (показан ниже, который я получил от http://www.firedartstudios.com/articles/read/php-security-how-to-safely-store-your-passwords ), в котором есть 3 функции. 1-й должен создать случайную соль, вторую для генерации хэша с использованием 1-й сгенерированной соли, а последний – проверить предоставленный пароль, сравнив его с хешированным паролем.
<?php /* Bcrypt Example */ class bcrypt { private $rounds; public function __construct($rounds = 12) { if(CRYPT_BLOWFISH != 1) { throw new Exception("Bcrypt is not supported on this server, please see the following to learn more: http://php.net/crypt"); } $this->rounds = $rounds; } /* Gen Salt */ public function genSalt() { /* openssl_random_pseudo_bytes(16) Fallback */ $seed = ''; for($i = 0; $i < 16; $i++) { $seed .= chr(mt_rand(0, 255)); } /* GenSalt */ $salt = substr(strtr(base64_encode($seed), '+', '.'), 0, 22); /* Return */ return $salt; } /* Gen Hash */ public function genHash($password) { /* Explain '$2y$' . $this->rounds . '$' */ /* 2a selects bcrypt algorithm */ /* $this->rounds is the workload factor */ /* GenHash */ $hash = crypt($password, '$2y$' . $this->rounds . '$' . $this->genSalt()); /* Return */ return $hash; } /* Verify Password */ public function verify($password, $existingHash) { /* Hash new password with old hash */ $hash = crypt($password, $existingHash); /* Do Hashs match? */ if($hash === $existingHash) { return true; } else { return false; } } } /* Next the Usage */ /* Start Instance */ $bcrypt = new bcrypt(12); /* Two create a Hash you do */ echo 'Bcrypt Password: ' . $bcrypt->genHash('password'); /* Two verify a hash you do */ $HashFromDB = $bcrypt->genHash('password'); /* This is an example you would draw the hash from your db */ echo 'Verify Password: ' . $bcrypt->verify('password', $HashFromDB); ?>
Теперь, если я создаю хэш с «паролем», например, я получаю хешированный пароль, который принимал соль Randmonly. Затем, если я снова введу «пароль» и воспользуюсь функцией проверки, я получаю истинное значение, означающее, что пароли совпадают. Если я введу неправильный пароль, я получаю false. Мой вопрос в том, как это возможно? Как насчет случайно сгенерированной соли? Почему это не имеет никакого эффекта?
Хороший взгляд на ценности, с которыми вы имеете дело. Полученная случайная соль будет, скажем:
abcdefg...
То, что подается в crypt
выглядит следующим образом:
crypt($password, '$2y$10$abcdefg...') | | | | | +- the salt | +- the cost parameter +- the algorithm type
Результат выглядит так:
$2y$10$abcdefg...123456789... | | | | | | | +- the password hash | | +- the salt | +- the cost parameter +- the algorithm type
Другими словами, первая часть результирующего хэша совпадает с исходным входом в функцию crypt
; он содержит тип и параметры алгоритма, случайную соль и результат хэша.
Input: $password + $2y$10$abcdefg... Output: $2y$10$abcdefg...123456789... ^^^^^^^^^^^^^^^^^ first part identical
Когда вы подтвердите пароль, вам понадобится повторная соль. Только с той же солью будет тот же самый хэш пароля с тем же хешем. И он все еще присутствует в хэше, в формате, который может быть передан в crypt
как это повторяет ту же операцию, что и при генерации хэша. Вот почему вам необходимо передать пароль и хеш в функцию проверки:
crypt($passwordToCheck, '$2y$10$abcdefg...123456789...')
crypt
берет первое определенное количество символов, вплоть до abcdefg...
и включает в abcdefg...
и отбрасывает остальных (поэтому соль должна быть фиксированным числом символов). Поэтому он равен той же операции, что и раньше:
crypt($passwordToCheck, '$2y$10$abcdefg...')
И будет генерировать тот же хеш, если и только если $passwordToCheck
– то же самое.