Второй аргумент crypt
не должен быть именем учетной записи пользователя.Это должна быть строка настроек .Строки настройки выглядят следующим образом:
$2b$07$fQuDK3TaQP4sw6IX6iVcTw
Часть $2b$07$
сообщает crypt
, какой алгоритм хеширования паролей использовать, а следующая строка случайных символов - salt .Соль должна быть разной для каждого пользователя, но она не должна иметь никакой связи с именем учетной записи пользователя.Технически это не должно быть случайным, но важно, чтобы оно было разным для каждого пользователя, и его нужно менять каждый раз, когда пользователь меняет свой пароль, поэтому лучше всего использовать длинную строку, взятую из криптографического 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
, документация на которую я ссылался выше, а у других другая версия , с тем же именем, выполняющая ту же работу, но с разными аргументами.Вычистите свой Autoconf skillz!)
Теперь вы знаете все это, я могу объяснить, почему
password = crypt("password chosen", "user's account name");
, казалось, работал, но усек пароль.Возможно, имена ваших учетных записей начинаются как минимум с двух буквенно-цифровых символов, верно?Например, "Ma[ya]"
или "zw[ol]"
?К сожалению, любые два алфавитно-цифровых символа составляют допустимую строку настроек ... которая выбирает один из самых старых и наименее безопасных алгоритмов хеширования паролей, известных науке, descrypt .(Это было очень хорошо, когда он был изобретен ... в середине 1970-х годов. В настоящее время он может быть взломан с помощью грубой силы независимо от того, какой пароль.) Одна из многих проблем этого алгоритмачто он усекает все пароли до восьми символов.asdf
и asdfhjkl
хешируют для разных вещей, но asdfhjkl
и asdfhjkl1234
хэшируют для одной и той же вещи.
Лекарство от этого заключается в использовании crypt_gensalt
или эквивалентного для выбора современного алгоритма.Все современные алгоритмы принимают произвольно длинные парольные фразы.