Проект: Tuna — менеджер паролей  Публичный пост для комнаты «Индихакеры»
20 февраля 2025  237
Tuna - менеджер паролей
https://tuna.am

Недавно в блоге у Вастрика вышла статья про End-to-end Шифрование, при этом у нас примерно в тоже время появился - Менеджер паролей.

Кажется это идеальное время рассказать про то почему мы его сделали и о его устройстве.

Что такое Tuna я уже ранее рассказывал тут, но напомню в 2х словах. Изначально мы делали сервис реверс-прокси туннелей, а-ля Ngrok, но как видите не смогли остановиться только на туннелях.

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

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

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

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

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

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

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

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

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

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

Архитектура

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

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

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

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

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

Начнём с задачи - иметь общие каталоги с паролями в команде. Из статьи Вастрика мы помним, что тут 2 пути:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Фух ...

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

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

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

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

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

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

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

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

https://my.tuna.am/password#2tIrpHCLZNoQGHFhRDIiLkInitp_aZh4Iv4OtO3SROk7FXdaib4yCyNP0zL/O1//t6k36G0=

Ссылка выше с пасхалкой, действует 30 дней, переходите

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

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


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

Какие планы ?

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

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

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

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


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

Связанные посты
2 комментария 👇

Классно, что пилите такой продукт, но мне как пользователю интересно, почему это решение лучше, чем развернуть Bitwarden на своём сервере?

  Развернуть 1 комментарий
🕵️ Юзер скрыл свои комментарии от публичного просмотра...

😎

Автор поста открыл его для большого интернета, но комментирование и движухи доступны только участникам Клуба

Что вообще здесь происходит?


Войти  или  Вступить в Клуб