Перейти к основному содержимому

🔐 Менеджер паролей - зачем мы его сделали и как он устроен

· 7 мин. чтения

Когда вы доверяете свои пароли внешнему сервису, главный вопрос — можно ли ему доверять. Поэтому мы решили открыто рассказать, как изнутри устроен Менеджер паролей Tuna: какими ключами и в каком порядке шифруются данные, что хранится у нас на сервере, а что — только у вас, и что произойдёт, если наша база данных утечёт. Цель простая — чтобы пользоваться менеджером было не страшно, потому что вы понимаете, как он работает.

Tuna — менеджер паролей
Коротко

Все ключи шифрования создаются на вашем устройстве и никогда не покидают клиент в открытом виде. На сервер уходит только зашифрованный текст, а Мастер-ключ есть только у вас. Это модель нулевого знания (zero-knowledge): даже если наша инфраструктура будет скомпрометирована и утечёт вся база данных — расшифровать ваши пароли без Мастер-ключа невозможно.

Нафига мы сделали менеджер паролей?

Мы много работали по фрилансу в разных компаниях, поэтому есть насмотренность как люди меняются корпоративными паролями к сервисам, инфраструктуре и прочему. Ну так вот, если в компании нет купленного 1Password или чего-то подобного (что там Дудь рекламирует), то это просто аншлаг.

  • Нет единого хранилища, чаще всего это просто какой-то 1 ответственный человек, если он уйдёт, то всё...
  • Пароли передают в чатиках Tg или Slack
  • При увольнении сотрудника, если есть какая то общая учётка от внешнего сервиса, приходится почти рассылать новый пароль всем.

Там ещё скоуп проблем, но это основное.

В общем посмотрели мы на это всё и подумали, что у нас 99% пользователей это разработчики, наверняка у них та же самая проблема. Есть потребность хранить какие то инфраструктурные пароли, SSH ключи, офисный WI-FI и так далее. Но не всегда есть доступные инструменты для безопасного и удобного способа делиться ими с командой, заказчиками, аудиторами или просто друзьями.

Так вот и решили, что надо — ну и сделали.

Сколько стоит?

Мы решили, что это будет базовым бесплатным функционалом в рамках нашей платформы.

Безопасность — это базовая потребность (даже по пирамиде Маслоу), и мы хотим, чтобы даже самые маленькие стартапы на 5 человек могли себе позволить безопасно хранить и обмениваться паролями в компании или друзьями.

Возможно позже мы введём какие то разумные ограничения или новые возможности которые будут доступны только с подпиской, но пока весь функционал доступен бесплатно всем. Вы можете зарегистрироваться, создать Команду, пригласить пользователей и завести общие каталоги с паролями без оформления подписки.

Архитектура

Что ж, ничего сложного, генерируем на клиенте какой-то ключ показываем его пользователю, нигде не сохраняем, этим ключом пользователь на клиенте шифрует пароли, в зашифрованном виде передаёт на сервер, мы храним. Когда пользователь хочет прочитать пароль, отдаём его, пользователь расшифровывает этот пароль своим ключом который есть только у него — профит.

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

Общие каталоги в команде

Вообще в этом параграфе мы разберём почти полное устройство, так как будем распутывать клубок из конца в начало.

Начнём с задачи — иметь общие каталоги с паролями в команде. Тут есть 2 пути:

  • Пароли должны быть зашифрованы 1 ключом который есть у всех.
  • При добавлении нового пользователя мы дублируем все пароли и шифруем его публичным ключом.

Второй поход нам не подходит, так как пользователь 1 должен иметь возможность редактировать пароль, а пользователь 2 должен сразу это видеть и наоборот. Значит — пароли должны быть зашифрованы одним ключом который есть у всех. Как такое провернуть? А вот так:

Пароли шифруются AES-ключом каталога, а сам AES-ключ — RSA-ключом пользователя

В итоге пароли шифруются симметричным AES ключом, назовём его — AES-ключ каталога. Но не храним же мы его в открытом виде? Верно, этот AES-ключ каталога на самом деле зашифрован RSA-ключом пользователя.

Распутываем клубок ...

Приватный RSA-ключ шифруется Мастер-ключом, публичный хранится в открытом виде

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

Итого, пользователь хранит:

  • свой Мастер-ключ

Итого, мы храним:

  • публичный RSA-ключ
  • зашифрованный приватный RSA-ключ
  • зашифрованный AES-ключ каталога
  • зашифрованный пароли

Давайте попробуем посмотреть картину в целом и собрать в кучу весь алгоритм что там вообще происходит?

Полная схема алгоритма работы менеджера паролей

Если коротко, то основная концепция в том, что на стороне сервера если что-то и хранится, то исключительно в зашифрованном виде, а на клиенте в открытом виде всё может существовать только в Runtime и перманентно тоже нигде не хранится.

Чтобы проще это понять нужно пройтись по шагам:

  • Пользователь инициирует менеджер паролей
  • На клиенте (браузер) генерируется пара RSA-ключей приватный и публичный.
  • На клиенте генерируется Мастер-ключ, пользователь должен сохранить его себе
  • На клиенте приватный RSA-ключ шифруется Мастер-ключом
  • На сервер передаётся зашифрованный приватный RSA-ключ и публичный RSA-ключ
  • Пользователь создаёт новый каталог
  • На клиенте генерируется AES-ключ каталога
  • На клиенте AES-ключ каталога шифруется публичным RSA-ключом
  • На клиенте пароли шифруются AES-ключом каталога

Когда нам надо сделать пароли общими, мы находим пользователя в команде, берём его публичный RSA-ключ, берём AES-ключ каталога расшифровываем его своим приватным RSA-ключом, шифруем публичным RSA-ключом нового пользователя и отправляем на сервер, на сервере у каталога появляется новый пользователь с AES-ключом каталога и новый пользователь теперь может расшифровать его своим приватным RSA-ключом, а затем и пароли зашифрованные AES-ключом каталога.

В итоге получается примерно вот такая колбаса:

Цепочка вложенного шифрования ключей и паролей

Фух ...

Делимся паролями наружу

Если с пользователями внутри команды разобрались, то как делиться паролями наружу, ведь у незарегистрированных пользователей нет RSA-ключей и они вообще ничего не знают?

Обмен паролем наружу по одноразовой ссылке

Тут мы приходим к тому нужно сделать копию пароля. Снова генерируем AES-ключ но в этот раз он будет только для 1 пароля. Зашифрованному паролю присваиваем UID и отправляем это на сервер.

Что знает клиент:

  • UID пароля
  • AES-ключ которым он зашифрован

Что знает сервер:

  • UID пароля
  • Зашифрованный пароль

Далее клиент генерирует ссылку, где часть URI — это UID пароля, а другая AES-ключ:

https://my.tuna.am/password#{UID}#{AES-ключ}

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

Да, формально мы можем расшифровать пароль в момент 1-го же обращения, так как в запросе мы увидим полную ссылку, но делать этого мы конечно не будем. В целом есть идеи как улучшить этот момент, но пока всё на этапе обсуждения. Тем не менее именно в базе данных всё зашифровано.

В базе данных всё хранится в зашифрованном виде

Думаю тут можно завершить с архитектурой и перейти дальше.

Какие планы?

Мы уже получили обратную связь от CTO одного из наших клиентов, с просьбой добавить поддержку TOTP (Time-based one-time Password), думаю добавим в ближайшем релизе. Это актуально если в компании есть какой-то сервис с одним аккаунтом и вход там с подтверждением через TOTP.

Думаем как сделать функционал Делимся паролями наружу более безопасным, но при этом таким же удобным.

Также есть планы внедрить работу с паролями в консольную утилиту tuna чтобы можно было получать пароли в консоли.

В целом продукт ещё в стадии Бета и мы активно собираем обратную связь.

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

Tuna — менеджер паролей

Оставьте отзыв

Если вам нравится пользоваться Tuna, или наоборот вы недовольны чем либо, то пожалуйста оставьте отзыв.

Помощь

Мы ценим наших пользователей и детально изучаем все обращения, если у вас возникли проблемы с tuna – обязательно свяжитесь с нами одним из способов: