Хранение пользователя и пароля в базе данных

Я создаю программное обеспечение с паролем пользователя+. После авторизации пользователь может получить доступ к некоторым полуобщинным службам, а также зашифровать некоторые файлы, к которым может обратиться только пользователь.

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

Вопрос в том, как сохранить эту комбинацию пользователя + пароль в потенциально незащищенной базе данных?

Я действительно не понимаю, что я должен раскрывать.

Скажем, я создаю расширенный ключ следующим образом:

salt = random 32 characters string (is it okay?)
key = hash(usr password + salt)
for 1 to 65000 do
  key = hash(key + usr password + salt)

Должен ли я хранить [пользователь открытого текста], [расширенный ключ] и [соль] в базе данных?

Кроме того, что я должен использовать для шифрования (с AES или Blowfish) некоторых файлов с использованием нового пароля каждый раз? Должен ли я генерировать новую соль и создавать новый расширенный ключ (пароль, сохраненный в памяти программы + соль)? И в этом случае, если я храню зашифрованный файл в базе данных, возможно, я должен хранить соль. База данных такая же, как и где я храню комбинацию пользователя + пароль.

Файл может быть дешифрован, только если кто-то может сгенерировать ключ, но он не знает пароль. Правильно?

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

Огромное спасибо!

Ответ 1

Crypto трудно понять, хорошо, что вы задаете вопросы.

Хранение паролей:. Пароли должны быть хэшированы с использованием алгоритма растяжения ключа. Как правило, вы хотите использовать библиотеку, а не реализовывать ее самостоятельно. Ключевые алгоритмы растяжения предназначены для пережевывания процессорных циклов, поэтому приятно оценивать их с помощью хорошего кода C. Если вы находитесь в системе Linux с glibc, вы можете использовать модуль crypt.crypt (читайте man crypt):

import crypt
encrypted = crypt.crypt(password, '$6$' + salt + '$')

Это возвращает строку ASCII, которую вы можете безопасно хранить в своей базе данных. ($6$ - расширение glibc, которое использует функцию растяжения ключа на основе SHA-512. Если у вас нет этого расширения, не используйте crypt.crypt). (Редактирование: алгоритм очень похож на тот, который вы задавали в своем вопросе. Однако наилучшей практикой обычно является то, что библиотека может делать это, а не сворачивать ваши собственные.)

Шифрование файлов: Не делайте этого самостоятельно. Установите GnuPG (или scrypt, bcrypt, ncrypt, что у вас есть). Есть несколько вещей, которые могут легко ошибиться при разработке собственного способа шифрования файлов. Эти инструменты используют надлежащие функции деривации ключей, хэши аутентификации и режимы шифрования без какой-либо дополнительной настройки. Это не библиотеки Python, а исполняемые файлы, поэтому вам придется написать оболочку, которая использует модуль subprocess.

Пароли в памяти: Нет. После того, как вы проверили пароль пользователя в базе данных паролей, конвертируйте пароль в ключ с помощью функции деривации ключа. Затем вы можете использовать ключ для разблокировки зашифрованных файлов, но вы больше не можете использовать его для возврата исходного пароля.

Ответ 2

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

Цель соли состоит в том, чтобы сделать грубую силу или диктаторские атаки намного сложнее. Вот почему он более безопасен, если хранить отдельно, чтобы избежать того, у кого есть как хэш-пароли, так и соответствующие соли.