Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → API-ключи: выпуск, хранение и отзыв

API-ключи: как выдавать и отзывать доступ для сервисов и интеграций

API-ключи: формат и энтропия, хеширование на стороне сервера, области действия, ротация, ограничения и аудит использования ключей.

Прямой ответ

API-ключ — долгосрочный секрет, который идентифицирует вызывающую сторону: партнёрскую интеграцию, фоновый сервис, скрипт автоматизации. В отличие от пользовательской сессии он живёт месяцами и обычно не имеет интерактивного подтверждения, поэтому требования к его защите выше.

Правила, которые определяют безопасность ключа:

  1. Достаточная энтропия. Не менее 128 бит случайности. Ключ должен быть непредсказуемым: схемы вида user_123_key недопустимы.
  2. Хранение только в виде хеша. Сервер хранит SHA-256(key), а не сам ключ. При утечке базы ключи нельзя использовать. Полный ключ показывается один раз — в момент создания.
  3. Области действия (scopes). Ключ даёт право на конкретный набор операций, а не на всё. Ключ «только чтение отчётов» не должен уметь удалять данные.
  4. Ограничение по ресурсам. Ключ привязан к владельцу и, при необходимости, к конкретным объектам или IP-диапазонам.
  5. Срок действия и ротация. Бессрочные ключи — накопленный риск. Практика: срок 90–365 дней, ротация с перекрытием, когда старый и новый ключ работают параллельно несколько дней.

Формат ключа удобно делать распознаваемым: префикс идентифицирует тип (sk_live_, sk_test_), что помогает находить утечки в логах и репозиториях и различать окружения.

import secrets, hashlib

def issue_key(owner_id: int, scopes: list[str], expires_in_days: int = 180) -> tuple[str, str]:
    raw = "sk_live_" + secrets.token_urlsafe(32)
    digest = hashlib.sha256(raw.encode()).hexdigest()
    db.insert("api_keys", owner_id=owner_id, key_hash=digest,
              scopes=",".join(scopes), expires_at=utcnow() + timedelta(days=expires_in_days))
    return raw, digest          # raw показываем один раз

Проверка на стороне сервера: вычисляем хеш от полученного ключа, ищем запись, проверяем срок, статус и наличие требуемого scope. Сравнение хешей — обычное, потому что сам ключ в базе не хранится и атака по времени на сравнение не даёт преимущества.

Практика: жизненный цикл ключа

Выпуск. Ключ создаётся в интерфейсе с явным выбором владельца, областей и срока. Полный ключ отображается один раз; повторный просмотр невозможен, только перевыпуск.

Передача и хранение у клиента. Ключ хранится в переменных окружения или в системе управления секретами, а не в коде и не в репозитории. Как организовать хранение секретов — в статье про Vault и SOPS.

Использование. Ключ передаётся в заголовке (Authorization: Bearer … или X-API-Key), не в URL: параметры запроса попадают в логи прокси и историю браузера.

Ограничения и наблюдение. Для каждого ключа обязательны rate limit и журнал вызовов. Внезапный рост числа запросов или запросы из новой сети — сигнал компрометации. Механику журнала см. в статье про audit log.

Отзыв. Мгновенная инвалидация по статусу, а не по удалению записи: удалённый ключ исчезает из журнала, и расследование становится невозможным.

CREATE TABLE api_keys (
  id          BIGSERIAL PRIMARY KEY,
  owner_id    BIGINT NOT NULL,
  key_hash    TEXT NOT NULL UNIQUE,
  prefix      TEXT NOT NULL,           -- первые 8 символов для идентификации
  scopes      TEXT NOT NULL,
  status      TEXT NOT NULL DEFAULT 'active',   -- active | revoked
  created_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
  expires_at  TIMESTAMPTZ,
  revoked_at  TIMESTAMPTZ,
  last_used_at TIMESTAMPTZ
);

Рекомендации:

  1. Разделяйте ключи по окружениям. sk_test_ не работает в проде и наоборот; это снижает ущерб от утечки тестового ключа.
  2. Не используйте API-ключ для пользователей. Для человека нужен интерактивный вход и сессия; ключ — для машин. Смешение ролей ломает и аудит, и отзыв — см. RBAC.
  3. Проверяйте права на каждый запрос. Наличие валидного ключа не означает права на конкретную операцию: проверка scope обязательна.
  4. Алертуйте на аномалии. Число 401/403, всплеск трафика по ключу, запросы из новой географии.
  5. Сканируйте репозитории на утечки. Префикс ключа делает такой поиск простым и позволяет автоматизировать обнаружение.

Практический сценарий: ключ партнёра утёк в публичный репозиторий

Контекст: интеграция партнёра; через неделю замечен аномальный трафик — массовая выгрузка отчётов.

  1. Обнаружение. Метрика запросов по ключу выросла в 40 раз, часть запросов шла с IP, которых раньше не было. В журнале видно чтение большого числа отчётов без характерной для партнёра паузы.
  2. Причина. Партнёр разместил ключ в конфигурационном файле публичного репозитория; ключ был бессрочным и имел scope на чтение всех отчётов.
  3. Действия. Ключ отозван (статус revoked, не удаление), выпущен новый с ограниченным scope и сроком 90 дней; добавлено ограничение по IP-диапазону партнёра и rate limit на ключ.
  4. Оценка ущерба. По журналу определили, какие отчёты читались; часть содержала персональные данные, что потребовало отдельной процедуры — см. маскирование PII.
  5. Профилактика. Ввели обязательный срок действия ключей, проверку репозиториев партнёров на секреты, алерт на всплеск трафика по ключу и требование хранить ключи только в системах управления секретами.

Вывод: компрометация ключа — вопрос времени, поэтому важнее не «не допустить утечку», а ограничить ущерб: срок действия, минимальные scopes, ограничения по сети и мгновенный отзыв.

FAQ

Чем API-ключ отличается от OAuth-токена? Ключ — долгосрочный секрет, обычно для машинного взаимодействия и без контекста пользователя. OAuth-токен выдаётся в результате авторизационного потока, имеет короткий срок и несёт информацию о согласиях пользователя. Для «сервис → сервис» часто достаточно ключа, для «приложение действует от имени пользователя» нужен OAuth.

Можно ли хранить ключи в коде приложения? Нет. Код попадает в репозитории, образы контейнеров и артефакты сборки. Ключи передаются через переменные окружения или систему управления секретами, а образы не должны содержать секретов.

Нужно ли хешировать ключи, если база защищена? Да. Защита базы снижает вероятность утечки, но не отменяет последствий: при компрометации бэкапа или реплики хешированные ключи бесполезны для атакующего. Стоимость реализации минимальна.

Как организовать ротацию без простоя? Выпускают второй ключ, переключают клиента, затем отзывают первый. На время перекрытия оба ключа активны. Автоматизация: уведомление за 30 дней до истечения и возможность выпустить замену заранее.

Источники: OWASP Secrets Management Cheat Sheet, OWASP API Security, Wikipedia (API key) — ссылки в шапке.