Гайды

Как безопасно хранить API-ключи — и почему .env во фронтенде не секрет

Иллюстрация: ключ в сейфе на серверной стороне, не в окне витрины

Самая дорогая ошибка новичка в вайб-кодинге — не баг в логике. Это слитый API-ключ. Кто-то подключает платный сервис (OpenAI, карты, отправку SMS), кладёт ключ «в .env, как все советуют», деплоит фронтенд — и через неделю получает счёт на сотни долларов. Ключ всё это время лежал на виду.

Вот в чём капкан: .env во фронтенде — это не секрет. При сборке его значения зашиваются прямо в JavaScript, который скачивает каждый посетитель. Открой DevTools → Sources, поищи свой ключ — и ты его там найдёшь. Разберём по шагам, как хранить ключи так, чтобы их не украли.

Шаг 1. Пойми, где выполняется твой код

Это главный шаг — остальное следует из него. Код живёт в двух местах:

  • Клиент (браузер/приложение) — всё, что туда попало, видно пользователю. Любой ключ здесь публичен по определению.
  • Сервер (бэкенд, edge-функция) — выполняется на машине, к которой у пользователя нет доступа. Только сюда можно класть секреты.

Правило, которое всё решает: секретный ключ должен жить и использоваться только на сервере. Если внешний API дёргается из браузера — ключ утечёт, без вариантов.

Шаг 2. Раздели ключи на публичные и секретные

Не все ключи одинаковы. Прежде чем что-то прятать, отсортируй:

  • Публичные ключи созданы, чтобы быть в браузере: anon-ключ Supabase, publishable-ключ Stripe, ключ карт с ограничением по домену. Их утечка — норма, они защищены другим способом (правами доступа, привязкой к домену).
  • Секретные ключи дают полный доступ: sk_-ключ Stripe, service-role Supabase, ключ OpenAI. Эти никогда не должны попадать на клиент.

Если не уверен — смотри документацию сервиса: там прямо написано, какой ключ «secret», а какой «publishable/public».

Шаг 3. Вынеси секрет в переменную окружения на сервере

Не пиши ключ строкой прямо в коде. Вынеси его в переменную окружения — и читай на сервере:

// серверный код (edge-функция, бэкенд) — НЕ браузер
const key = process.env.OPENAI_API_KEY;

Во фреймворках есть важная деталь именования. Переменные с префиксом вроде NEXT_PUBLIC_ или VITE_ намеренно попадают в браузерный бандл. Секреты так называть нельзя — иначе ты сам отправишь их на клиент. Секрет = имя без публичного префикса.

Шаг 4. Закрой .env от git

Файл .env не должен попасть в репозиторий — иначе ключ навсегда останется в истории git, даже если ты его потом удалишь. Добавь в .gitignore:

.env
.env.local

А в репо положи .env.example с пустыми значениями — как шпаргалку, какие переменные нужны. Пустыми, не настоящими.

Шаг 5. Положи секреты в панель хостинга

Локальный .env остаётся на твоей машине. На проде секреты задают через панель хостинга — там для этого есть специальное место:

  • Vercel/Netlify → Settings → Environment Variables.
  • Supabase → секреты Edge Functions (supabase secrets set).

Хостинг подставит их в окружение при запуске — в код они так и не попадут.

Шаг 6. Проксируй внешний API через свой сервер

А как же тогда вызвать платный API, если ключ нельзя дать браузеру? Через прокси: браузер зовёт твой сервер, а сервер уже с ключом идёт во внешний API.

браузер → твоя edge-функция (тут ключ) → API OpenAI → ответ → браузер

Ключ ни на секунду не покидает сервер. Заодно тут удобно поставить лимиты, чтобы один пользователь не сжёг весь твой бюджет. Как технически устроен такой вызов — в гайде как подключить API.

Что получится

Если прошёл все шаги: секретные ключи живут только на сервере, в git их нет, на проде они в панели хостинга, а браузер ходит во внешние сервисы через твой прокси. Открыв DevTools, пользователь не найдёт ни одного секрета — только публичные ключи, которым это и положено.

А если ключ всё-таки утёк (закоммитил, показал на стриме) — не прячь, отзови и перевыпусти его в панели сервиса немедленно. Удалить из кода мало: то, что побывало в git или в эфире, считай скомпрометированным. Эта проверка входит в чеклист безопасности перед запуском.

Частые вопросы

Я добавил ключ в .env — этого достаточно?

Зависит от того, где этот .env. Во фронтенде (Vite, Next.js с NEXT_PUBLIC_) — нет, значение уедет в бандл к пользователю. На сервере (бэкенд, edge-функция) — да, если файл при этом в .gitignore и не попал в git.

Можно ли просто запутать ключ в коде, чтобы не нашли?

Нет. Обфускация (запутывание) — это не защита: всё, что выполняется в браузере, можно размотать. Любой инструмент разработчика покажет настоящее значение. Единственная реальная защита — вообще не отправлять секрет на клиент.

Я случайно закоммитил ключ — что делать?

Сначала перевыпусти ключ в панели сервиса — старый сразу станет бесполезным. Только потом чисти историю git. Порядок важен: пока старый ключ жив, неважно, удалил ты его из кода или нет — он уже мог быть скопирован ботами, которые сканируют публичные репозитории.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →