Второй аргумент crypt
не должен быть именем учетной записи пользователя. Предполагается, что это строка настройки. Строки настройки выглядят так:
$2b$07$fQuDK3TaQP4sw6IX6iVcTw
Часть $2b$07$
сообщает crypt
, какой алгоритм хеширования паролей использовать, а следующая за ней строка случайных символов представляет собой соль. Соль должна быть разной для каждого пользователя, но не должна иметь никакой связи с именем учетной записи пользователя. Технически это не обязательно должно быть случайным, но очень важно, чтобы оно было разным для каждого пользователя, и оно должно меняться каждый раз, когда пользователь меняет свой пароль, поэтому лучше всего использовать длинную строку, полученную из криптографического PRNG.
Когда вы аутентифицируете пользователя, который ранее входил в систему, вы используете сохраненный хешированный пароль в качестве строки настройки:
char *new_hash = crypt("password typed in", "stored hash");
if (new_hash && !strcmp(new_hash, "stored hash")) {
// user has successfully logged in
}
Это работает, потому что сохраненный хешированный пароль всегда начинается со строки настроек, которая использовалась для его создания в первую очередь, а crypt
закодирован так, чтобы смотреть только на часть строки настроек.
(Также обратите внимание на нулевую проверку; некоторые реализации crypt
могут дать сбой и сообщить об ошибке, возвращая нулевой указатель.)
Когда вы создаете новую учетную запись или меняете пароль, вам необходимо сгенерировать новую строку настроек. Если у вас есть функция crypt_gensalt
, используйте ее:
char *new_setting = crypt_gensalt("$2b$", 0, 0, 0);
if (new_setting) {
char *new_hash = crypt("user's new password", new_setting);
// ...
} else {
// halt and catch fire
}
Если у вас нет crypt_gensalt
, к сожалению, вам придется реализовать его самостоятельно. (Что еще хуже, в некоторых Unix-системах есть crypt_gensalt
, на документацию которого я ссылался выше, а в других есть другая версия с тем же именем, выполняющая ту же работу, но с другими аргументами. Пора стряхнуть пыль с ваших навыков Autoconfz!)
Теперь вы знаете все это, я могу объяснить, почему
password = crypt("password chosen", "user's account name");
казалось, работает, но обрезает пароль. Имена ваших учетных записей пользователей, вероятно, начинаются как минимум с двух буквенно-цифровых символов, верно? Например, "Ma[ya]"
или "zw[ol]"
? К сожалению, любые два буквенно-цифровых символа составляют допустимую строку настройки... которая выбирает один из самых старых и наименее безопасных алгоритмов хеширования паролей, известных науке, descrypt. (Это было довольно хорошо, когда его изобрели... в середине 1970-х годов. Сейчас его можно взломать методом грубой силы независимо от пароля.) Одна из многих проблем с этим алгоритмом заключается в том, что он усекает все пароли до восьми символов. asdf
и asdfhjkl
хешируют разные вещи, а asdfhjkl
и asdfhjkl1234
хешируют одно и то же.
Лекарством от этого является использование crypt_gensalt
или его эквивалента для выбора современного алгоритма. Все современные алгоритмы принимают сколь угодно длинные парольные фразы.
person
zwol
schedule
23.09.2019
crypt()
(который, кстати, работает не так, как вы предполагаете, так что вам лучше прочитать его документация). - person Eugene Sh.   schedule 23.09.2019crypt
и друзей, достаточно старая, достаточно загадочная или просто-неправильная, так что я действительно не виню OP за то, что он запутался. Однако не отвечать на комментарии — это справедливая критика. - person zwol   schedule 23.09.2019