Модуль Python crypt — как правильно использовать соли?

StackOverflow https://stackoverflow.com/questions/329956

Вопрос

Во-первых, контекст:Я пытаюсь создать инструмент на основе командной строки (Linux), который требует входа в систему.Учетные записи на этом инструменте не имеют ничего общего с учетными записями на уровне системы-ни одно из этого не рассматривает /etc /passwd.

Я планирую хранить учетные записи пользователей в текстовом файле, используя тот же формат (примерно), что и /etc/passwd.

Несмотря на то, что я не использовал файлы паролей на системном уровне, использование Crypt, казалось, была хорошей практикой, в отличие от хранения паролей в ClareText.(В то время как Crypt, безусловно, лучше, чем хранение паролей в Clartext, я открыт для других способов этого.)

Мои знания крипты основаны на этом:https://docs.python.org/2/library/crypt.html

Кажется, в документации запрашивается нечто невозможное:«Рекомендуется использовать полный пароль в качестве соли при проверке пароля».

Хм?Если я создаю зациклированный пароль (как в при создании записи пользователя), как я могу использовать скрипкий пароль в качестве соли?Его еще не существует.(Я предполагаю, что вы должны использовать одну и ту же соль для создания и проверки пароля.)

Я пробовал использовать пароль в виде открытого текста в качестве соли.Это работает, но имеет две проблемы;один легко преодолимый, а другой серьезный:

1) Первые две буквы пароля с открытым текстом включены в куриный пароль.Вы можете исправить это, не записав первые два символа в файл:

user_record = '%s:%s:%s' % (user_name, crypted_pw[2:], user_type)

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

Лучшая практика, которую я смог получить, - это использовать первые два символа из имени пользователя в качестве соли.Будет ли это уместно, или есть что -то, что я пропустил, что делает это плохим ходом?

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

Это было полезно?

Решение

Для использования модуля crypt:

ГЕНЕРИРУЯ зашифрованный пароль, вы предоставляете соль.С тем же успехом можно было бы повысить устойчивость к брутфорсу случайным образом, если это соответствует перечисленным условиям.При ПРОВЕРКЕ пароля вы должны указать значение из getpwname, если вы работаете в системе, которая поддерживает соли большего размера и не генерировала его самостоятельно.

Общие комментарии:

Если это не имеет ничего общего с реальным входом в систему, ничто не мешает вам использовать более надежный метод, чем crypt.Вы можете случайным образом сгенерировать N символов соли для каждого пользователя, которые будут объединены с паролем пользователя в хеше SHA-1.

string_to_hash = user.stored_salt + entered_password
successful_login = (sha1(string_to_hash) == user.stored_password_hash)

ОБНОВЛЯТЬ:Хотя этот метод гораздо более безопасен против радужных таблиц, описанный выше метод все еще имеет криптографические недостатки.Правильное применение алгоритма HMAC может еще больше повысить вашу безопасность, но это выходит за рамки моей компетенции.

Другие советы

Python crypt() — это оболочка системной функции crypt().На справочной странице Linux crypt():

char *crypt(const char *key, const char *salt);

key is a user’s typed password.
salt is a two-character string chosen from the set [a–zA–Z0–9./]. 
This string is used to perturb the algorithm in one of 4096 
different ways.

Акцент делается на "двухсимвольный нить".Теперь, если вы посмотрите на поведение crypt() в Python:

>>> crypt.crypt("Hello", "World")
'Wo5pEi/H5/mxU'
>>> crypt.crypt("Hello", "ABCDE")
'AB/uOsC7P93EI'

вы обнаружите, что первые два символа результата всегда совпадают с первыми двумя символами исходной соли, которые действительно образуют истинную двухсимвольную соль.То есть результат crypt() имеет вид 2char-salt + зашифрованный-проход.Следовательно, нет никакой разницы в результате, если вместо передачи двухсимвольной соли или исходной многосимвольной соли вы передаете весь зашифрованный пароль.

Примечание:набор [a–zA–Z0–9./] содержит 64 символа, а 64*64=4096.Вот как два персонажи относятся к "4096 различные пути".

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

Ваша идея о том, чтобы начальная соль основывалась на имени пользователя, кажется нормальной.

Вот несколько общих советов по добавлению паролей:

  1. Обычно соли используются для приготовления ранбоу столы слишком дорого для расчета.Итак, вам следует добавить немного случайной соли ко всем хешам ваших паролей и просто хранить ее в виде открытого текста рядом с хешированным значением пароля.
  2. Использовать HMAC — это хороший стандарт, и он более безопасен, чем объединение пароля и соли.
  3. Используйте SHA1:MD5 сломан.Без обид, если вы это знали, просто будьте внимательны.;)

я не стал бы пусть соль будет функцией пароля.Злоумышленнику придется создать радужную таблицу, чтобы иметь базу данных паролей для мгновенного поиска, но сделать это придется только один раз.Если вы выберете случайное 32-битное целое число, им придется сгенерировать 2^32 таблицы, что (в отличие от детерминированной соли) требует слишком много памяти (и времени).

Для большей прочности вы можете заставить модуль crypt использовать md5, используя соль в формате.

$1$ABCDEFGH$

где ABCDEFGH — ваша солевая строка.

>>> p = crypt.crypt('password', '$1$s8Ty3/f$')
>>> p
Out: '$1$s8Ty3/f$0H/M0JswK9pl3X/e.n55G1'
>>> p == crypt.crypt('password', p)
Out: True

(обратите внимание, что это расширение GNU для crypt, см. «man crypt» в системе Linux).MD5 (а теперь даже SHA1) могут быть «сломанными», но они по-прежнему относительно хороши для хэшей паролей, а md5 по-прежнему является стандартом для локальных паролей Linux.

Пароль или что-либо, полученное из него, никогда не следует использовать в качестве соли.Соль для конкретного пароля должна быть непредсказуемой.

Имя пользователя или часть имени пользователя допустимы, но еще лучше — случайные байты из криптографического ГСЧ.

Используйте PBKDF2, см. этот комментарий в другом потоке (включая реализацию Python).

Взгляните на статью TrueCrypt объяснил Бьёрн Эдстрем.Он содержит понятное объяснение того, как работает truecrypt, и простую реализацию некоторых функций truecrypt на Python. включая управление паролями.

Он говорит о модуле Python crypt(), а не о TrueCrypt в Python.

По умолчанию crypt.crypt() в Python 2 не очень безопасно и статья объясняет, как могут работать более безопасные альтернативы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top