Известны ли проблемы с функцией C crypt ()? - PullRequest
0 голосов
/ 23 сентября 2019

Я использую crypt () для шифрования паролей для моего проекта.Когда пароль выбирается пользователем, он шифруется следующим образом:

password = crypt(<password chosen>, <user's account name>)

Проблема заключается в том, что пользователь входит в систему, используя свой пароль.Если то, что они вводят, не совпадает с их паролем, следует ввести это, если проверить:

if (strcmp(crypt(<what user types in as password>, <user's account name>), <user's encrypted password>)) {
   //...
}

Это не в одном определенном сценарии.Допустим, их пароль «asdf».Если они вводят «asdf» с произвольными конечными символами, такими как «asdffffff» или «asdf339sfd», он все равно принимает пароль.Кажется, все игнорируется после «asdf».

Это известная проблема с crypt?Есть ли другой способ шифрования паролей?

1 Ответ

5 голосов
/ 23 сентября 2019

Второй аргумент 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 или эквивалентного для выбора современного алгоритма.Все современные алгоритмы принимают произвольно длинные парольные фразы.

...