Практическое руководство для разработчиков
Права API key в OpenAI-совместимом API: принцип минимального доступа
Права API key в OpenAI-совместимом API — это не только переключатель «ключ работает или нет». Один общий секрет в браузере, CI и трёх сервисах не позволяет понять, кто вызвал модель, ограничить дорогой маршрут или быстро отключить один интеграционный модуль. Практичный подход строит границу в вашем backend: внешний ключ RussiaAPI остаётся только там, а приложения получают собственные ограниченные учётные данные. Так команда управляет моделями, бюджетом и журналом без раскрытия секрета gateway.
RUSSIAAPI_API_KEY на сервере; не передавайте внешние ключи, cookie, пароли, коды подтверждения или лишние персональные данные.Сначала разделите два вида ключей
Есть ключ, которым ваш сервер обращается к gateway, и есть учётные данные, которыми внутренние сервисы или пользователи обращаются к вашему backend. Это разные границы. RUSSIAAPI_API_KEY хранится только в серверном secret store или переменной окружения процесса. Он не попадает в JavaScript браузера, мобильное приложение, публичный репозиторий, скриншот панели или тикет поддержки. Внутренний токен может идентифицировать конкретный сервис, tenant или среду, но не должен автоматически давать полный доступ к ключу gateway.
Не предполагаете, что каждый OpenAI-совместимый endpoint или модель поддерживает одни и те же механизмы прав. Если в консоли RussiaAPI есть роли, ограничения ключа или бюджет, сверяйте их с текущей документацией и договором перед включением. Если такой возможности нет, ограничения всё равно можно применить в собственном серверном proxy: разрешать только нужные модели, размер запроса и назначение маршрута. Это не делает gateway официальным сервисом производителя и не отменяет правила вашего продукта.
Опишите разрешения как короткую политику
Политика должна отвечать на четыре вопроса: кто вызывает маршрут, какие model ID разрешены, какой максимум запроса допустим и сколько операций или расхода разрешено за период. Для чат-бота поддержки достаточно одного текстового маршрута и небольшой allowlist; сервис генерации видео может требовать отдельного server-side маршрута, очереди и другого бюджета. Не выдавайте «на всякий случай» доступ ко всем моделям. Новая модель, инструмент или видео-операция — отдельное решение с владельцем и тестом.
Собирайте policy по идентификатору приложения, а не по значению, которое присылает браузер. Клиент может попросить model ID, но сервер сверяет его с разрешённым списком и при необходимости выбирает безопасное значение сам. Логируйте имя policy, tenant, модель, HTTP-класс и агрегированный расход; не пишите Authorization, полный prompt, ответ модели или личные файлы. Такой журнал помогает ответить, почему запрос отклонён, и дополняет разделение ключей в команде.
Поставьте proxy между приложением и gateway
Server-side proxy — место, где проверяются пользовательская сессия, внутренний токен, лимит, бюджет и допустимый payload. Только после этой проверки он добавляет заголовок авторизации RussiaAPI. Не проксируйте произвольный URL и не принимайте от клиента заголовок Authorization: иначе приложение сможет использовать чужой или вышестоящий ключ. Вместо этого сформируйте разрешённый запрос сами и верните нейтральную ошибку без технических деталей поставщика.
Ниже минимальный пример для Node.js 18+. Он намеренно использует демонстрационный внутренний токен из переменной окружения и статическую policy; для production замените его базой или системой идентификации, храните только хэш токена и добавьте устойчивый счётчик бюджета. Код не утверждает, что RussiaAPI предоставляет scopes ключей: scopes здесь применяет ваше приложение. Перед запуском задайте INTERNAL_BOT_TOKEN, RUSSIAAPI_API_KEY и существующий в вашем каталоге RUSSIAAPI_TEXT_MODEL.
import { createServer } from 'node:http';
const policy = {
token: process.env.INTERNAL_BOT_TOKEN,
allowedModels: new Set([process.env.RUSSIAAPI_TEXT_MODEL]),
maxChars: 4_000
};
createServer(async (req, res) => {
if (req.method !== 'POST' || req.url !== '/assistant') return res.writeHead(404).end();
const chunks = []; for await (const chunk of req) chunks.push(chunk);
const input = JSON.parse(Buffer.concat(chunks).toString('utf8'));
if (req.headers['x-internal-token'] !== policy.token ||
!policy.allowedModels.has(input.model) || typeof input.message !== 'string' || input.message.length > policy.maxChars) {
return res.writeHead(403, { 'content-type': 'application/json' }).end(JSON.stringify({ error: 'policy_denied' }));
}
const upstream = await fetch('https://russiaapi.com/v1/chat/completions', {
method: 'POST', headers: { authorization: `Bearer ${process.env.RUSSIAAPI_API_KEY}`, 'content-type': 'application/json' },
body: JSON.stringify({ model: input.model, messages: [{ role: 'user', content: input.message }] }), signal: AbortSignal.timeout(12_000)
});
if (!upstream.ok) return res.writeHead(503).end(JSON.stringify({ error: 'assistant_unavailable' }));
const data = await upstream.json();
res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify({ text: data.choices?.[0]?.message?.content ?? '' }));
}).listen(3000);Пример проверяет вход до исходящего вызова и не возвращает тело ошибки gateway. В реальном сервисе добавьте аутентификацию пользователя, rate limit по tenant, ограничение длины сообщения, аудит изменения policy и отдельную очередь для длительных задач. Ограничение ключа не заменяет проверку бизнес-прав: доступ к одному model ID не означает право читать чужой проект или скачивать чужой результат.
Ротация без остановки всех интеграций
Ротация начинается с инвентаря: владелец, назначение, среда, дата выдачи и путь отзыва. Один глобальный ключ для всех сервисов делает ротацию аварией, поэтому полезно разделять внутренние токены по приложениям даже тогда, когда gateway-key один. При утечке вы отключаете конкретный внутренний токен, находите затронутые операции по безопасному ID и меняете секрет gateway по вашему процессу. Не пытайтесь «проверить» секрет, отправляя его в чат, форму или сторонний диагностический сервис.
Плановая замена обычно имеет короткий переходный период: backend умеет читать новую активную запись и, при необходимости, предыдущую только для верификации внутренних токенов; затем старая запись отзывается. Для ключа gateway используйте процедуру, которую поддерживает ваша консоль, и протестируйте замену синтетическим запросом до отключения старого значения. Практика безопасного хранения разобрана в руководстве по API key.
Проверяйте границы регулярно
Каждый релиз policy должен иметь тесты: неразрешённая модель даёт контролируемый отказ, слишком длинный ввод не доходит до gateway, токен одного tenant не читает расход другого, а журнал не содержит секрет. Периодически просматривайте неиспользуемые токены и устаревшие allowlist. Нельзя считать ключ «безопасным навсегда» только потому, что он лежит в переменной окружения: важны доступ к окружению, журналы, CI, резервные копии и процесс отзыва.
- Внешний ключ RussiaAPI существует только на сервере и никогда не передаётся клиенту.
- У каждого внутреннего клиента есть назначение, владелец и минимальная policy.
- Backend применяет allowlist моделей, лимит размера и бюджет до запроса.
- Логи содержат безопасные метаданные, но не ключ, prompt, cookie или полный ответ.
- Есть проверенный путь отзыва и синтетический тест после ротации.
Принцип минимального доступа снижает радиус ошибки, но не является обходом лимитов, условий поставщика или применимых требований. Если нужная функция недоступна по вашему контракту, отразите это в продукте и выберите допустимый сценарий.
Проверьте сценарий в RussiaAPI
Создайте собственный тестовый ключ в консоли, проверьте текущий каталог моделей и контракт callback, затем выполните минимальный server-side тест на синтетических данных. Расширяйте доступ и нагрузку только после измеримой проверки.
Открыть консоль RussiaAPIFAQ
Можно ли положить ключ RussiaAPI в frontend?
Нет. Любой ключ в браузере или мобильном приложении может быть извлечён и использован вне вашей policy. Клиент обращается к вашему backend, а сервер хранит ключ gateway и применяет ограничения.
Поддерживает ли RussiaAPI права ключей?
Проверяйте текущую консоль, документацию и ваш договор. Статья описывает безопасный application-level proxy, который полезен независимо от того, есть ли у gateway отдельные scopes.
Нужен ли отдельный ключ для каждого пользователя?
Не всегда. Начните с разделения по сервису, tenant и среде. Если пользователю требуется индивидуальная квота или отзыв, связывайте её с вашей аутентификацией и внутренней policy, не выдавая ему ключ gateway.