Как безопасно хранить API-ключи в React-приложении

Современные веб-приложения часто обращаются к внешним API. Ключи и секреты связывают запросы с вашей учётной записью и являются чувствительной информацией. Если ключ попадёт в публичный репозиторий или в финальную сборку фронтенда, злоумышленник сможет отправлять запросы от вашего имени.
Основная идея
- Публичные переменные окружения (например, для конфигурации клиента) допустимы во фронтенде.
- Секреты должны оставаться на сервере и никогда не попадать в статические файлы, которые обслуживаются пользователям.
Важно: .env в корне React-приложения при сборке попадает в файлы сборки и может быть просмотрен в браузере.
Добавление переменных окружения в проект на create-react-app
create-react-app (CRA) из коробки поддерживает переменные окружения. CRA подхватывает переменные, начинающиеся с REACT_APP, и делает их доступными через process.env в коде клиента.
Создайте файл .env в корне проекта и добавьте переменные с префиксом REACT_APP:
REACT_APP_API_KEY=your_api_keyИспользование в коде React:
const API_KEY = process.env.REACT_APP_API_KEYДобавьте файл .env в .gitignore, чтобы не коммитить его в репозиторий:
# Скрываем локальные переменные
.envОднако помните: при выполнении сборки CRA в production все переменные, считанные из .env, инлайнятся в файлы сборки и становятся доступными клиенту.
Почему нельзя хранить секреты в .env на фронтенде
При сборке фронтенда значения окружения инкапсулируются в JavaScript, который загружается в браузер. Любой пользователь может открыть инструменты разработчика и найти эти строки. Поэтому хранить секреты (ключи доступа, приватные токены) в клиентском .env — плохая практика.
Архитектуры для безопасного хранения ключей
Ниже — распространённые и надёжные подходы.
1. Бэкенд-прокси
Идея: фронтенд делает запрос на ваш сервер, сервер использует секреты для вызова внешнего API, затем возвращает результат фронтенду.
Пример на Node.js + Express:
// .env на сервере
API_URL=https://secret-api.example.com/data
// server.js
const express = require('express')
const fetch = require('node-fetch')
const app = express()
const apiURL = process.env.API_URL
app.get('/data', async (req, res) => {
try {
const response = await fetch(apiURL)
const data = await response.json()
res.json({ data })
} catch (err) {
res.status(500).json({ error: 'Ошибка при обращении к API' })
}
})
app.listen(3000)Фронтенд запрашивает ваш маршрут:
const data = await fetch('https://your-backend.example.com/data')
const json = await data.json()Преимущества: секреты остаются на сервере; можно централизовать логику, кеширование и обработку ошибок.
2. Next.js и серверный рендеринг
Next.js позволяет обращаться к секретным переменным на сервере — например, в getStaticProps или в API-роутах внутри папки pages/api.
Пример getStaticProps:
export async function getStaticProps() {
const res = await fetch(process.env.API_URL)
const data = await res.json()
return { props: { data } }
}
function Home({ data }) {
return (
{/* рендер данных */}
)
}
export default HomeЗдесь process.env.API_URL доступна только на сервере во время сборки.
Пример API-роута:
// pages/api/getData.js
export default async function handler(req, res) {
const response = await fetch(process.env.API_URL)
const data = await response.json()
return res.status(200).json({ data })
}Фронтенд вызывает /api/getData, и ключи остаются на сервере.
3. Управляемые секреты в облаке
Платформы типа AWS Secrets Manager, Azure Key Vault, Google Secret Manager или хостинги (Vercel, Netlify) позволяют управлять секретами и выдавать их только окружению выполнения. Эти сервисы часто интегрируются с CI/CD и уменьшают риск утечки.
Практический чеклист перед деплоем
Frontend developer:
- Убедиться, что в коде нет явных секретов (ключей, паролей).
- Проверить, что .env добавлен в .gitignore.
- Использовать переменные с REACT_APP только для неприлично-секретных значений (например, ID публичного клиентa).
Backend developer / DevOps:
- Хранить секреты в защищённом хранилище окружения или секрет менеджере.
- Ограничить доступ к секретам по ролям.
- Искать утечки в истории коммитов и, при необходимости, ротировать ключи.
Мини-процедура (SOP) по внедрению прокси
- Создайте бэкенд-эндпоинт, который выполняет обращение к внешнему API.
- Поместите секреты в серверный .env или в облачный Secret Manager.
- Настройте CORS/аутентификацию между фронтендом и бэкендом.
- Обновите фронтенд, чтобы вызывать ваш бэкенд, а не внешнее API напрямую.
- Протестируйте сценарии ошибок и задержки, добавьте кэширование на сервере при необходимости.
- После развертывания отозовите старые ключи, если они были скомпрометированы.
Критерии приёмки
- Фронтенд не содержит секретных строк после проверки сборки.
- Все запросы к защищённому API проходят через ваш бэкенд или серверный слой.
- Секреты хранятся в защищённом месте с ограничением доступа.
Когда описанные подходы не подходят
- Если вы используете сторонний SDK, который обязательно требует ключ в клиенте (например, публичные API с ограничением по origin) — убедитесь, что ключ минимально привилегирован и можно настроить ограничения по домену и квотам.
- Для мобильных приложений нужно всё равно считать, что клиент может быть скомпрометирован; используйте серверные проверки и ротацию ключей.
Ментальные модели и эмпирические правила
- Ментальная модель «публичное против приватного»: всё, что выполняется в браузере, считается публичным.
- Правило пяти минут: если ключ позволяет выполнить критичную операцию и при утечке потребуются немедленные действия — не храните его в клиенте.
Безопасность и конфиденциальность
- Минимизируйте права ключей (принцип наименьших привилегий).
- Логируйте обращения к API и анализируйте аномалии.
- Планируйте ротацию ключей и автоматизацию отзыва при подозрении на утечку.
Примечание о персональных данных: API-ключ сам по себе обычно не является персональным данными, но если через API передаётся ПДн (персональные данные), соблюдайте требования GDPR/локального законодательства: защищайте канал, журналируйте доступ и минимизируйте хранение.
Шпаргалка по командам и настройкам
- .gitignore: добавьте “.env” и любые локальные файлы конфигурации.
- CI/CD: храните переменные окружения в настройках пайплайна, не в репозитории.
- Логи: не выводите секреты в логах.
Короткий глоссарий
- Переменная окружения: набор ключ=значение, доступный процессу во время выполнения.
- Секрет: значение, которое предоставляет доступ к ресурсам и должно быть защищено.
- Прокси: серверный слой, который выполняет запросы от имени клиента, скрывая секреты.
Итог
Хранение секретов в коде фронтенда ведёт к утечкам и злоупотреблениям. Для безопасной работы используйте бэкенд-прокси, серверные функции (Next.js) или управляющие сервисы секретов от облачного провайдера. Регулярно проверяйте репозиторий на утечки и внедряйте практики ротации ключей.
Важно: при обнаружении утечки немедленно отозвите и поменяйте ключи, проверьте историю доступа и скорректируйте права.
Похожие материалы
man в Linux: как читать и выходить
Как изменить звук уведомлений в iOS 17.2
Обновление watchOS на Apple Watch — инструкция
Серийный номер ПК в Linux — как найти
Уведомления о звуках на Android — настройка и советы