Прямой ответ
API-ключ — долгосрочный секрет, который идентифицирует вызывающую сторону: партнёрскую интеграцию, фоновый сервис, скрипт автоматизации. В отличие от пользовательской сессии он живёт месяцами и обычно не имеет интерактивного подтверждения, поэтому требования к его защите выше.
Правила, которые определяют безопасность ключа:
- Достаточная энтропия. Не менее 128 бит случайности. Ключ должен быть непредсказуемым: схемы вида
user_123_keyнедопустимы. - Хранение только в виде хеша. Сервер хранит
SHA-256(key), а не сам ключ. При утечке базы ключи нельзя использовать. Полный ключ показывается один раз — в момент создания. - Области действия (scopes). Ключ даёт право на конкретный набор операций, а не на всё. Ключ «только чтение отчётов» не должен уметь удалять данные.
- Ограничение по ресурсам. Ключ привязан к владельцу и, при необходимости, к конкретным объектам или IP-диапазонам.
- Срок действия и ротация. Бессрочные ключи — накопленный риск. Практика: срок 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
);
Рекомендации:
- Разделяйте ключи по окружениям.
sk_test_не работает в проде и наоборот; это снижает ущерб от утечки тестового ключа. - Не используйте API-ключ для пользователей. Для человека нужен интерактивный вход и сессия; ключ — для машин. Смешение ролей ломает и аудит, и отзыв — см. RBAC.
- Проверяйте права на каждый запрос. Наличие валидного ключа не означает права на конкретную операцию: проверка scope обязательна.
- Алертуйте на аномалии. Число 401/403, всплеск трафика по ключу, запросы из новой географии.
- Сканируйте репозитории на утечки. Префикс ключа делает такой поиск простым и позволяет автоматизировать обнаружение.
Практический сценарий: ключ партнёра утёк в публичный репозиторий
Контекст: интеграция партнёра; через неделю замечен аномальный трафик — массовая выгрузка отчётов.
- Обнаружение. Метрика запросов по ключу выросла в 40 раз, часть запросов шла с IP, которых раньше не было. В журнале видно чтение большого числа отчётов без характерной для партнёра паузы.
- Причина. Партнёр разместил ключ в конфигурационном файле публичного репозитория; ключ был бессрочным и имел scope на чтение всех отчётов.
- Действия. Ключ отозван (статус
revoked, не удаление), выпущен новый с ограниченным scope и сроком 90 дней; добавлено ограничение по IP-диапазону партнёра и rate limit на ключ. - Оценка ущерба. По журналу определили, какие отчёты читались; часть содержала персональные данные, что потребовало отдельной процедуры — см. маскирование PII.
- Профилактика. Ввели обязательный срок действия ключей, проверку репозиториев партнёров на секреты, алерт на всплеск трафика по ключу и требование хранить ключи только в системах управления секретами.
Вывод: компрометация ключа — вопрос времени, поэтому важнее не «не допустить утечку», а ограничить ущерб: срок действия, минимальные scopes, ограничения по сети и мгновенный отзыв.
FAQ
Чем API-ключ отличается от OAuth-токена? Ключ — долгосрочный секрет, обычно для машинного взаимодействия и без контекста пользователя. OAuth-токен выдаётся в результате авторизационного потока, имеет короткий срок и несёт информацию о согласиях пользователя. Для «сервис → сервис» часто достаточно ключа, для «приложение действует от имени пользователя» нужен OAuth.
Можно ли хранить ключи в коде приложения? Нет. Код попадает в репозитории, образы контейнеров и артефакты сборки. Ключи передаются через переменные окружения или систему управления секретами, а образы не должны содержать секретов.
Нужно ли хешировать ключи, если база защищена? Да. Защита базы снижает вероятность утечки, но не отменяет последствий: при компрометации бэкапа или реплики хешированные ключи бесполезны для атакующего. Стоимость реализации минимальна.
Как организовать ротацию без простоя? Выпускают второй ключ, переключают клиента, затем отзывают первый. На время перекрытия оба ключа активны. Автоматизация: уведомление за 30 дней до истечения и возможность выпустить замену заранее.
Источники: OWASP Secrets Management Cheat Sheet, OWASP API Security, Wikipedia (API key) — ссылки в шапке.