Создание безопасной веб-системы управления паролями с возможностью обмена данными между пользователями - PullRequest
6 голосов
/ 27 марта 2011

Заранее извиняюсь за входящий Wall-O-Text . Это (по крайней мере, для меня) довольно сложная проблема, над которой я довольно много думал. Вы можете прочитать мой вопрос, а также увидеть тестовую реализацию в Ruby (очень спешно построенную, не поддерживаемую базой данных, и, вероятно, очень уродливую) на этой GitHub Gist , если вы так склонны.


Введение

Представьте себе, что для создания веб-системы управления паролями нужно было (через SSL! :) со следующими требованиями:

  1. Отдельные пользователи входят в систему, используя свой уникальный проход фраза.
  2. Этой парольной фразы должно быть достаточно, чтобы позволить пользователю использовать систему эффективно (например, со смартфона и т. д.) - суть в том, что они не должен иметь при себе файл ключа.
  3. Пользователи могут хранить в системе биты произвольной длины («записи»).
  4. Записи зашифрованы в базе данных таким образом, что нет достаточно информации только в базе данных или приложении, чтобы прочитать зашифрованные записи.
  5. Пользователи должны иметь возможность «делиться» записями с другими пользователями системы. чтобы другие пользователи могли читать содержимое записи.

Я не специалист по криптографии. Подумав некоторое время, я подошел со следующим. Мой вопрос : безопасна ли эта реализация? Я что-то упустил? Если да, то является ли приведенная выше спецификация вообще осуществимой? Или это излишество?

База данных

База данных настроена так:

+------------------------------------------------------------------------------+
|  users                                                                       |
+---------+--------------+--------------+---------------+----------------------+
| salt    | pub_key      | enc_priv_key | priv_key_hmac |                      |
+---------+--------------+--------------+---------------+----------------------+
|  entries                                                                     |
+---------+--------------+--------------+---------------+----------+-----------+
| user_id | parent_entry | enc_sym_key  | sym_key_sig   | enc_data | data_hmac |
+---------+--------------+--------------+---------------+----------+-----------+

Основные случаи использования

Давайте представим двух пользователей системы, Алису и Боба.

Bob регистрируется на сайте :

  • Боб вводит пароль. Этот пароль отправляется на сервер (но не сохранены).
  • Сервер генерирует случайную соль и сохраняет ее в поле salt.
  • Сервер генерирует хэш SHA-256 для пароля и соли Боба.
  • Сервер генерирует пару ключей RSA. Открытый ключ хранится как обычный текст в поле pub_key. Закрытый ключ шифруется через AES-256 используя хеш, сгенерированный из пароля Боба и соли в качестве ключа и хранится в поле enc_priv_key.
  • Сервер генерирует код аутентификации сообщений на основе хэша для Боба закрытый ключ, используя пароль Боба и соль в качестве ключа, и сохраняет его в поле priv_key_hmac.

Боб сохраняет запись в системе :

  • Боб вводит некоторые данные для хранения вместе со своим паролем. Эти данные отправляются на сервер.
  • Сервер генерирует ключ, который будет использоваться в качестве ключа для шифрования AES-256.
  • Сервер использует этот ключ для шифрования данных и сохраняет результат в поле enc_data.
  • Сервер генерирует код аутентификации сообщений на основе хеш-функции для данные с использованием сгенерированного ключа и сохраняет его в поле data_hmac.
  • Симметричный ключ, используемый для шифрования данных, зашифрован с помощью открытого Боба ключ и сохраняется в поле enc_sym_key.
  • Сервер использует личный ключ Боба для генерации подписи симметричный ключ.

Боб получает свою сохраненную запись :

  • Боб вводит свой пароль и идентификатор записи для извлечения.
  • Сервер генерирует хэш SHA-256 для пароля и соли Боба.
  • Зашифрованный закрытый ключ Боба расшифровывается с помощью шифрования AES-256 с использованием хэш.
  • Сервер проверяет, что зашифрованный закрытый ключ Боба не был вмешиваться, проверяя HMAC в priv_key_hmac.
  • Сервер расшифровывает симметричный ключ, хранящийся в поле enc_sym_key используя личный ключ Боба.
  • Сервер проверяет, что зашифрованный симметричный ключ не был взломан с проверкой подписи в sym_key_sign с использованием открытого ключа Боба.
  • Сервер расшифровывает данные с помощью симметричного ключа.
  • Сервер проверяет, что зашифрованные данные не были подделаны, проверяя HMAC, сохраненный в поле data_hmac.
  • Сервер возвращает расшифрованные данные Бобу.

Боб делится записью с Алисой :

  • Боб хочет, чтобы Алиса имела доступ к записи, которой он владеет.Он вводит свой пароль и идентификатор записи для совместного использования.
  • Данные для записи расшифровываются с использованием метода из «Боб получает свою сохраненную запись».
  • ДляАлиса так же, как в «Боб хранит запись в системе», со следующими исключениями:
    1. Запись parent_entry установлена ​​на запись Боба.
    2. Подпись для симметричногоключ рассчитывается с использованием личного ключа Боба (поскольку личный ключ Алисы недоступен Бобу).
    3. Когда Алиса получает доступ к этой новой записи, существование ненулевого parent_entry заставляет систему использовать открытый ключ Боба.проверить подпись (поскольку его закрытый ключ использовался для ее создания).

Боб изменяет данные в своей общей записи :

  • Боб решает изменить данные в записи, которой он поделился с Алисой.Боб указывает идентификатор записи для изменения и новые данные, которые он должен содержать.
  • Система перезаписывает данные, созданные в «Боб сохраняет запись в системе».
  • Система находит каждую запись с помощьюparent_entry равно записи, которая была только что изменена, и для каждой перезаписывает данные, созданные в «Боб разделяет запись с Алисой».

Анализ

Преимущества:

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

Недостатки / проблемы (о которых я могу думать):

  • Если общая запись изменена, система должна повторношифровать каждую дочернюю запись;при большом количестве пользователей, разделяющих данные, это потенциально может быть вычислительно дорогим.
  • Общие записи зависят от открытого ключа родительского пользователя для проверки подписи.Если пользователь удален или его ключ изменен, подписи недействительны.

Повторяется после введения: мой вопрос: безопасна ли эта реализация?Я что-то пропустил?Если да, то является ли приведенная выше спецификация вообще осуществимой?Или это перебор?

Спасибо за то, что выложили это так долго.Мне интересно ваше мнение!Я на правильном пути или полный идиот?ВАМ РЕШАТЬ!:)

Ответы [ 3 ]

1 голос
/ 28 марта 2011

На самом деле вам не нужно дублировать что-либо, кроме enc_sym_key, когда вы делитесь записью с Алисой - поскольку симметричный ключ никогда не используется повторно более чем для одной записи, вам нужна только одна копия зашифрованных данных.

1 голос
/ 27 марта 2011

Нет внутривенного хранения? Я думаю, вы могли бы использовать AES-256-ECB, но это позволяет пользователям хранить только 32-байтовые пароли, и вам нужно убедиться, что сгенерированный закрытый ключ используется только для одного шифрования. (В этом отношении ваш текущий дизайн кажется безопасным, но если вы хотите разрешить пароли длиной более 32 байт или когда-либо подумайте о том, чтобы этот ключ выполнял двойную функцию, вам нужно будет хранить IV для каждого шифрование с его помощью.)

Я не вижу значения безопасности priv_key_hmac и data_hmac; если был изменен либо личный ключ, либо зашифрованные данные, то вывод мусора будет происходить в результате расшифровки с помощью личного ключа или симметричного ключа. Боб, несомненно, будет подозрительным, когда не сможет понять, как набрать символ BEL. :) (Увидят ли люди когда-нибудь результат? Человек, вероятно, поймет, что возвращенный пароль неверен без необходимости объяснения. Компьютер не может определить разницу, поэтому, если автоматизированные системы когда-либо будут использовать полученные пароли, тогда, конечно, сохраняйте поля.)

Нет механизма для "Я забыл свой пароль". Убедитесь, что ваши пользователи знают, что восстановление их данных невозможно, если они забыли свой пароль. В наши дни пользователи обнимаются и могут ожидать, что они также будут обременены вашим сервисом.

Я не вижу, чтобы пользователи указывали , какую запись Боб хочет расшифровать. Вы должны сохранить имя или, как это делает ssh(1) в known_hosts, хешированную версию имени для каждой записи. Непосредственное сохранение имени приведет к удалению операции SHA-256, но компрометация базы данных, сообщающая о незашифрованных именах сервисов, с которыми у пользователя есть учетные записи, может быть абсолютно вредной. (Возможно, онлайн-сопровождение, оффшорный банк или бойцовский клуб.)

0 голосов
/ 06 апреля 2012

Почему бы не использовать сертификаты для обмена данными между пользователями? Использование сертификатов PKCS # 12 для хранения PEM и закрытых ключей пользователей и PEM для каждого пользователя или для каждого сайта может подписывать и шифровать данные для проверки и безопасности данных.

Сценарий для иллюстрации.

Боб хочет поделиться с Алисой без чтения Евы.

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

Кроме того, зачем хранить соль или iv? Оба из них, хранящиеся вместе с данными в состоянии покоя, будут доступны в случае компрометации БД.

Лучшие практики ...

  1. Использовать набор ключей для каждой учетной записи пользователя для хранения других открытых ключей / сертификатов PEM
  2. Использовать шифрование с открытым ключом только для обмена информацией между учетными записями
  3. Шифрование данных с помощью закрытого ключа пользователя, который не подлежит разделению между учетными записями.
  4. НЕ использовать AES, RSA или любое другое обратимое шифрование для хранения пароля
  5. Для дальнейшего улучшения алгоритма хеширования пароля должны использоваться специальные соли пользователя, и НЕ должны храниться
  6. Использование AES с использованием пароля для всего сайта МОЖЕТ быть использовано для хранения данных в состоянии покоя для дальнейшего повышения безопасности (но вы столкнетесь с проблемой, описанной в разделе CONS)
...