Правильно ли я использую функцию crypt () в PHP? - PullRequest
17 голосов
/ 29 сентября 2010

Я использовал PHP crypt() как способ хранения и проверки паролей в моей базе данных.Я использую хеширование для других вещей, но crypt() для паролей.Документация не очень хорошая, и, похоже, много споров.Я использую Blowfish и две соли, чтобы зашифровать пароль и сохранить его в базе данных.Прежде чем хранить соль и зашифрованный пароль (как соленый хеш), но понял, что это избыточно, потому что соль является частью строки зашифрованного пароля.

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

function crypt_password($password) {
if ($password) {
    //find the longest valid salt allowed by server
    $max_salt = CRYPT_SALT_LENGTH;

    //blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 base 64
    $blowfish = '$2a$10$';

    //get the longest salt, could set to 22 crypt ignores extra data
    $salt = get_salt ( $max_salt );

    //get a second salt to strengthen password
    $salt2 = get_salt ( 30 ); //set to whatever


    //append salt2 data to the password, and crypt using salt, results in a 60 char output
    $crypt_pass = crypt ( $password . $salt2, $blowfish . $salt );

    //insert crypt pass along with salt2 into database.
    $sql = "insert into database....";

    return true;
    }
}  


function get_salt($length) {
$options = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';

$salt = '';

for($i = 0; $i <= $length; $i ++) {
    $options = str_shuffle ( $options );
    $salt .= $options [rand ( 0, 63 )];
}
return $salt;
}

function verify_password($input_password)
{
if($input_password)
{
    //get stored crypt pass,and salt2 from the database
    $stored_password = 'somethingfromdatabase';
    $stored_salt2 = 'somethingelsefromdatabase';

    //compare the crypt of input+stored_salt2 to the stored crypt password
    if (crypt($input_password . $stored_salt2, $stored_password) == $stored_password) {
        //authenticated
        return true;
    }
    else return false;
}
else return false;
}

Ответы [ 5 ]

15 голосов
/ 29 сентября 2010

Вам действительно стоит взглянуть на PHPASS: http://www.openwall.com/phpass/ Это фреймворк для хеширования паролей с использованием crypt (), который используется в таких проектах, как Wordpress и phpBB.

Также есть отличная статьяэтот сайт о хешировании, посоле и растяжении пароля с использованием crypt (): http://www.openwall.com/articles/PHP-Users-Passwords

ОБНОВЛЕНИЕ: В настоящее время существует альтернатива для библиотеки PHPASS.В следующей версии PHP есть специальные функции для хеширования и проверки паролей (с использованием bcrypt): http://www.php.net/manual/en/ref.password.php. Существует библиотека совместимости, которая реализует эти функции для PHP 5.3.7+: https://github.com/ircmaxell/password_compat

11 голосов
/ 30 сентября 2010

Вы можете использовать crypt() в порядке.crypt($input, $stored) == $stored - это способ, которым она предназначена для использования.

Ваша функция get_salt() невелика, поскольку она использует часто плохую функцию rand().Вам следует рассмотреть возможность использования более сильной случайной функции, например openssl_random_pseudo_bytes().

3 голосов
/ 29 сентября 2010

Идея радужной таблицы заключается в том, что злоумышленник может создать таблицу со всеми возможными паролями и их хэшами дома.

* 1003 Е.Г. *

PASSWORD HASH
iloveSO  gjroewjgo
password knbnogjwm
secret   gjroehghe
jbieber  rewgroewj

и т.д.

С помощью этой таблицы злоумышленник может быстро преобразовать любой хэш в пароль. Радужный стол использует некоторые приемы, так что не все хэши нужно хранить, но он все равно вычисляет все хеши заранее.

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

Таким образом, соль не является дополнительным паролем, известным только приложению, она предназначена для изменения хеш-функции, чтобы она была нестандартной.

2 голосов
/ 29 сентября 2010

Это неправильное использование crypt (), потому что вы используете устаревший примитив.Blowfish очень старый, twofish является заменой, и даже он старый, потому что Threefish почти завершена.Вы должны использовать члена семейства sha2, оба sha256 или sha512 - хороший выбор.crypt () может использоваться с sha256 или sha512, вы должны использовать параметры CRYPT_SHA256 CRYPT_SHA512 соответственно.

Кроме того, ваши соли имеют очень малое соотношение энтропии / размера, вы используете только буквенно-цифровой набор, который является шуткой, потому что буквенно-цифровые радужные таблицы являются наиболее распространенными.Вы должны использовать полный байт, который base256, и я рекомендую соль длиной 256 байт.Имейте в виду, что все хеш-функции по определению являются бинарно-безопасными, поэтому вам не нужно беспокоиться о нулевых байтах и ​​тому подобном.

0 голосов
/ 12 июня 2012

Используйте SHA-512 (если доступно) с солью, которая включает time () и openssl_random_pseudo_bytes ().Crypt консолидирован / эффективен, потому что возвращает соль, вставленную с хешированной строкой.

...