> MARAT_SHVETS.portfolio
> ← все новости

Vault: как мы делали свой менеджер паролей для команды

Раньше пароли команды жили в заметках и переписках. Сделали свой self-hosted менеджер паролей с шифрованием AES-256-GCM и деривацией ключа сразу из трёх независимых секретов — рассказываем, с какими проблемами столкнулись: смена схемы деривации на лету, хранение ключевого файла и безопасный шаринг записей в команде.

Почему мы вообще решили делать своё хранилище

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

Готовые менеджеры паролей нам не подошли: либо облако и доверие чужим серверам, либо self-hosted решения с интерфейсом и функциями не под наш процесс. Нужен был свой инструмент — со своими пользователями, ролями и возможностью безопасно шарить доступы внутри команды.

Как выбирали шифрование

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

Мы остановились на AES-256-GCM — он даёт не только конфиденциальность, но и проверку целостности (authentication tag), то есть подмену зашифрованных данных легко обнаружить. Каждая запись шифруется со своим случайным IV, поэтому одинаковые пароли не превращаются в одинаковые шифротексты.

Ключ шифрования нигде не хранится в явном виде — он выводится на лету через PBKDF2-SHA512 с 310 000 итераций из комбинации сразу трёх независимых секретов:

мастер-пароль пользователя
секретный "перец" (pepper), который знает только сервер
секрет из отдельного ключевого файла — назовём его ***.key — который генерируется автоматически при первом запуске

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

С какими сложностями столкнулись

Смена схемы деривации ключа на лету. Когда мы усилили схему (добавили третий секрет — ключевой файл), встал вопрос: что делать с уже зашифрованными данными первых пользователей? Полная переиндексация базы "на живую" рискованна. Решили сделать миграцию: старая схема деривации осталась в коде только как одноразовый путь для пересчёта, а новые записи используют исключительно усиленную схему.

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

Шаринг записей внутри команды. Личные пароли шифруются ключом, привязанным к конкретному пользователю, — сервер не может прочитать их напрямую. Но как тогда поделиться записью с коллегой, если ни у кого из вас нет ключа друг друга? Для расшаренных копий мы сделали отдельный механизм, в котором сервер способен их расшифровать. Это осознанный компромисс: общая часть паролей защищена немного слабее личной, зато шаринг работает просто и надёжно — и мы сознательно выбрали такой баланс, а не спрятали это ограничение.

Что дальше

Сейчас в Vault уже есть двухфакторная аутентификация, генератор паролей и оценка их надёжности. Дальше в планах — аудит-лог действий и более гибкие права доступа для команд.

Спасибо, что читаете. Если найдёте дыру — пишите, разберёмся.

← все новости→ написать мне