Мы открыли код шифрования своего хранилища API-ключей — и честно написали, чего он не гарантирует

от автора

Мы делаем proxykey — credential proxy: настоящие API-ключи лежат у нас зашифрованными, а приложения и ИИ-агенты ходят с отзываемыми виртуальными токенами. Недавно мы писали здесь про саму схему. Под ней и в личках всплыл один и тот же вопрос — самый правильный вопрос к любому такому сервису:

«А вы сами можете прочитать мои ключи?»

Короткий честный ответ: технически — да. И вместо того чтобы прятать это в маркетинговый туман, мы сделали две вещи: опубликовали крипто-модуль целиком и написали страницу с моделью угроз, где этот пункт стоит первым и жирным. Этот пост — о том, почему так, и что именно мы открыли.

Почему «zero-knowledge» здесь невозможен в принципе

Прокси обязан расшифровать ключ, чтобы подставить его в запрос к провайдеру — в этом вся его работа. Менеджер паролей может быть zero-knowledge: серверу ваш пароль не нужен. Credential proxy — не может: в момент запроса плейнтекст ключа существует в памяти процесса.

Из этого следует неудобная, но железная логика: процесс с полным доступом — а значит, и оператор сервера — в принципе способен получить открытый текст. Это свойство архитектуры, а не недоработка. И оно одинаково для всех hosted-решений этого класса — секрет-менеджеров, прокси, облачных хранилищ. Разница только в том, кто говорит об этом прямо.

Что тогда защищает шифрование

От вполне конкретных и куда более вероятных сценариев:

Сценарий

Защищено?

Утечка дампа БД

✅ секреты зашифрованы, мастер-ключа в базе нет

Кража бэкапов

✅ те же шифртексты без ключа

Слив логов

✅ ключей и auth-заголовков в логах нет

Компрометация только БД

✅ без KEK из окружения процесса шифртексты бесполезны

Утечка виртуального токена

✅ привязка к IP, лимиты, отзыв в один клик

Полная компрометация сервера / злонамеренный оператор

❌ честно: нет

Полная версия таблицы — на странице безопасности.

Что мы открыли

Репозиторий proxykey-crypto — ровно тот модуль конвертного шифрования, который шифрует секреты у нас в проде. 450 строк TypeScript вместе с тестами, без зависимостей кроме node:crypto:

  • на каждый секрет — свой DEK, плейнтекст шифруется AES-256-GCM с AAD = id секрета (шифртекст нельзя тихо переставить в чужую запись);

  • DEK обёрнут мастер-ключом (KEK), который живёт только в окружении процесса — в базе его нет;

  • расшифровка — в памяти на время одного запроса, DEK и копия плейнтекста зануляются в finally на любом пути, включая исключения;

  • виртуальные токены в базе — только SHA-256-хэши;

  • 18 тестов: roundtrip, подмена шифртекста/тега/обёртки, чужой AAD, неверная версия ключа.

Чего открытый код НЕ гарантирует

Тоже прямым текстом, потому что это вторая половина честности:

  1. Открытый код — не доказательство. Вы можете отревьюить схему, но криптографически доказать, что на сервере исполняется именно этот код, репозиторий не может. Это жест прозрачности, не аттестация.

  2. fill(0) — best-effort. V8 мог успеть скопировать буферы внутри своих операций; а строка с расшифрованным ключом в JS неизменяемая — её нельзя затереть, она живёт до сборщика мусора. Мы сузили окно, но не закрыли его — и говорим это вслух.

  3. Проверяется длина KEK, но не его энтропия. KDF там нет намеренно: мастер-ключ обязан быть случайным ключом (openssl rand -base64 32), а не паролем.

В README репозитория есть раздел «Design notes» с ответами на стандартные вопросы ревьюеров — границы random-nonce для GCM, почему обёртка DEK не привязана к AAD (ради будущей ротации KEK), и так далее. Если найдёте, к чему придраться сверх этого — идите в issues, это лучший вклад в общую безопасность.

Как снизить даже «оператора»

Практичный остаток для тех, кто пользуется любым hosted-хранилищем ключей, не только нашим:

  • заводите скоуп-ключи, а не мастер-ключи: проектный ключ OpenAI с бюджетом $20 вместо ключа всего аккаунта — тогда даже полная компрометация хранилища стоит вам $20, а не всё;

  • ставьте лимиты на стороне провайдера — вторая линия после лимитов хранилища;

  • ротируйте оригиналы — перевыпуск у провайдера обнуляет ценность всего, что могло утечь раньше;

  • не доверяете вообще — рациональная позиция: схема воспроизводима, крипто-модуль открыт, соберите свою инсталляцию.

Диклеймер

Мы — авторы proxykey (proxykey.org). Сервис бесплатный. Пост — не «у нас безопасно, доверьтесь», а ровно наоборот: вот граница, до которой безопасно, вот код, вот что остаётся на доверии. Нам кажется, так честнее — и полезнее для всех, кто выбирает, где хранить ключи.

ссылка на оригинал статьи https://habr.com/ru/articles/1056134/