Безопасность
Здесь нечего принимать на веру
Ниже конкретные решения и то, чем проверяется каждое: формат хранения зафиксирован тестовыми векторами, поведение API — контрактными тестами против спецификации, инварианты данных — триггерами в PostgreSQL. В конце — отдельный блок о том, чего мы не утверждаем.
Хранение значений
Конвертное шифрование
Каждое поле шифруется собственным рабочим ключом на AES-256-GCM, а рабочий ключ — мастер-ключом инстанса. Ротация мастер-ключа перешифровывает только ключи, а не терабайты содержимого.
Контекст обязателен
В аутентификацию входит тройка «секрет, версия, ключ». Валидный шифротекст одной записи нельзя подставить вместо другой: расшифровка просто не пройдёт. Пустой контекст отвергается на уровне криптопримитива.
Свой вектор на каждое поле
Блоб самодостаточен: версия формата, вектор инициализации и тег лежат внутри. Общий вектор на запись — классический путь к повторному использованию nonce в GCM; форматом он исключён.
Формат зафиксирован векторами
Эталонные векторы лежат в репозитории и проверяются на каждом прогоне. Раскладка меняется только с увеличением номера версии формата — старые данные читаются всегда.
Токены не хранятся
В базе только хеш: утечка дампа не даёт рабочих токенов. Показывается токен ровно один раз — в момент создания.
Пароли пользователей
Argon2id, отдельно от секретов. Пароль входа не годится для сейфа принципиально: он доходит до сервера, поэтому у сейфа отдельный мастер-пароль.
Доступ и наблюдаемость
Иммутабельность на уровне базы
Запрет на изменение содержимого версии и границы тенанта закрыты триггерами PostgreSQL. Ошибка в приложении не сможет переписать историю.
Имена не перебираются
Отсутствующий секрет и секрет без выданных прав отвечают одинаково — по ответу нельзя составить каталог чужих имён.
Лимиты запросов
Настраиваемые лимиты защищают от перебора и от фан-аута десятков потребителей; неудачные попытки аутентификации считаются отдельно от успешных запросов.
Журнал с отказами
Записывается и выдача, и отказ. Для расследования важнее второе: попытка прочитать чужое видна сразу.
Подпись доставки
Вебхуки подписываются Ed25519 ключом инстанса; назначение подписи входит в подписываемые байты, поэтому подпись одного типа сообщения нельзя предъявить как подпись другого.
Обновления и зависимости
Только стандартная криптография Go, без самописных примитивов и CGO. Линтер и сканер уязвимостей проходят на каждом изменении кода.
Что мы не утверждаем
Независимый криптографический аудит ещё не проводился — он в плане до того, как сейф паролей начнёт продвигаться как отдельный продукт. Сертификаций и аттестаций у продукта нет; если они нужны вашему контуру, напишите — обсудим сроки и формат.