Перейти к содержимому

Безопасность

Контракт определяет ровно две схемы безопасности, и обе несут один и тот же секрет:

СхемаЗаголовокПримечания
ApiKeyHeaderX-API-KeyРекомендуется.
BearerAuthAuthorization: BearerЭквивалентна. Используйте, когда клиентская библиотека требует bearer-токен.

Обе формы соответствуют одним и тем же учётным данным. GET /v1/products — единственный эндпоинт, принимающий неаутентифицированный вызов.

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

API-ключ Zelnum — это ck_ и следом 48 символов: 51 в общей сложности. Всё, что короче, ключом не является; это полезная проверка, когда менеджер секретов портит значение.

НужноНельзя
Хранить его в менеджере секретов или переменной окруженияКласть его в репозиторий, читаемый пользователями файл конфигурации или лог CI
Отправлять его со своего сервераКласть его в JavaScript браузера, сборку мобильного приложения или публичный клиент любого рода
Читать api_key_id, когда нужно идентифицировать ключВставлять сам ключ в обращение в поддержку
Скрывать его в логахЛогировать заголовки запросов целиком

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

База данных хранит хеш SHA-256 и 9-символьный отображаемый префикс, но никогда само значение, поэтому утёкший дамп не даёт никому работоспособный токен. Обратная сторона: ни один эндпоинт не может вернуть ваш ключ; если вы его потеряли, вы его меняете.

Окно терминала
curl -X GET "https://api.zelnum.com/api/v1/api-key" \
-H "X-API-Key: YOUR_KEY_HERE"

Ответ содержит api_key_id, masked_key, last_used и created_at — для последнего выданного активного ключа в аккаунте. Эндпоинт сообщает об одном ключе, поэтому читайте это как «ключ, которым я пользовался бы прямо сейчас», а не как инвентаризацию. Чтобы увидеть все ключи, используйте консоль.

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

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

Действие в консолиРезультат
СоздатьДобавляет ключ. Каждый существующий ключ продолжает работать.
ПерегенерироватьДеактивирует этот ключ и выдаёт замену с тем же именем. Оригинал сразу перестаёт работать.
УдалитьУдаляет ключ безвозвратно.

Это даёт две формы смены ключа, и выбор в том, можете ли вы позволить себе окно перекрытия.

Создать второй ключ — поэтапная смена, предпочтительный вариант:

  1. Создайте новый ключ в консоли. Больше ничего не меняется; старый ключ по-прежнему аутентифицирует.
  2. Разместите новое значение везде, где оно нужно — серверы приложений, воркеры, cron-задачи, скрипты по расписанию — пока не активируя его.
  3. Переключите деплой. Проверяйте через GET /v1/api-key, пока он не сообщит новый api_key_id, с учётом пятиминутной гранулярности last_used.
  4. Удалите старый ключ, когда им уже ничего не вызывается. Именно этот шаг фактически удаляет учётные данные — смена ключа не завершена, пока он не сделан.

Перегенерировать на месте — когда старое значение должно умереть немедленно:

Используйте это, когда ключ был раскрыт и любое дальнейшее его действие — риск.

  1. Примите разрыв. Старый ключ перестаёт работать в момент перегенерации, поэтому каждый компонент, всё ещё хранящий его, возвращает 401 unauthorized, пока не будет переразвёрнут. Перекрытия нет по замыслу.
  2. Перегенерируйте в консоли и сразу скопируйте открытое значение из баннера — оно показывается там и больше нигде и никогда.
  3. Разверните новое значение, затем убедитесь, что нигде больше не логируется 401.

Каждый эндпоинт работает по HTTPS. Прослушивателя открытого текста нет, и ни один эндпоинт не принимает понижение, поэтому не существует конфигурации, в которой ключ передаётся в незашифрованном виде.

Если вы ставите прокси или шлюз перед API, терминируйте TLS на периферии и пересылайте заголовок X-API-Key — не переписывайте его и не добавляйте в логи входящих запросов.

Что вы отправляете и как долго это хранится

Заголовок раздела «Что вы отправляете и как долго это хранится»

Входные данные API — телефонные номера и email-адреса, то есть персональные данные в большинстве юрисдикций. Два следствия:

  • Отправляйте только необходимое. Проверке нужен идентификатор и ничего больше. Не добавляйте в тело запроса идентификатор пользователя, внутреннюю ссылку или свободные метаданные: они не сохраняются как поле, а лишь расширяют утечку из ваших собственных логов.
  • Знайте сроки хранения. Логи realtime и результаты повторов по идемпотентности хранятся 30 дней по умолчанию, а файлы пакетных результатов — 7 дней (result_retention_days). По истечении этих сроков записи исчезают, поэтому экспортируйте всё, что обязаны хранить.

Считайте номер чувствительным и в своих системах. Результат проверки сообщает наблюдателю, зарегистрирован ли конкретный человек на конкретной платформе, а пара «идентификатор и вердикт» раскрывает больше, чем любая из половин по отдельности.

Это свойство безопасности не меньше, чем биллинга: Idempotency-Key делает повтор безопасным, поэтому сетевой сбой или нетерпеливый оператор не могут превратить одно списание в два. Никогда не создавайте новый ключ для повтора запроса, исход которого вы не наблюдали — см. Идемпотентность и повторы.