MAATRIX / Блог / Секрет утёк, но сервис живой: как понять, пользовались им или нет

Секрет утёк, но сервис живой: как понять, пользовались им или нет

MAATRIX

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

Утечка — это ещё не инцидент с ущербом

Между «секрет оказался в открытом доступе» и «секретом воспользовался злоумышленник» большая разница, и её часто стирают в панике. Ключ мог пролежать в публичном репозитории неделю и остаться незамеченным — ботов, сканирующих GitHub и Pastebin на предмет токенов, много, но они не всеведущи, и не каждая находка означает, что кто-то успел ей воспользоваться до вашей ротации.

Есть и обратная ошибка — считать, что раз явных проблем не видно (сервер не упал, счёт за облако не вырос), значит, всё в порядке. Аккуратный злоумышленник не станет майнить крипту на видном месте — он тихо выгрузит данные, заведёт бэкдор-пользователя с ограниченными правами или соберёт информацию для следующего этапа атаки. Отсутствие явного ущерба — не доказательство отсутствия использования.

Поэтому задача расследования — не «есть ли проблема», а «можем ли мы предъявить конкретные доказательства использования, и если нет — можем ли доказать обратное». Это разные вопросы, и второй обычно оказывается сложнее первого.

Зафиксируйте, что именно утекло и когда

Прежде чем лезть в логи, нужно точно определить окно риска и объём прав скомпрометированного секрета — без этого поиск превращается в перебор наугад.

Момент появления секрета в открытом виде. Это не всегда момент его создания. Для утечки через git — смотрите не дату коммита в текущей ветке, а git log --all --full-history -- путь/к/файлу, потому что секрет мог попасть в историю давно, а обнаружиться только сейчас при сканировании. Для утечки через лог сборки CI — время, когда лог стал доступен (публичный раннер, публичный артефакт), а не время самой сборки.

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

Объём прав ключа. Это определяет, что вообще нужно проверять:

Тип секретаНа что обычно даёт доступЧто проверять при подозрении на утечку
Cloud API-ключ (AWS/GCP/Yandex Cloud)Создание/удаление ресурсов, чтение данных, IAMЛоги создания ресурсов, новые IAM-пользователи и роли, изменения биллинга
Токен CI/CDПуш в registry, деплой, доступ к секретам пайплайнаИстория джобов, изменения в переменных окружения проекта, новые раннеры
API-ключ SaaS-сервиса (email-рассылки, платежи, мессенджеры)Отправка сообщений/писем от вашего имени, чтение данных клиентовИсходящие события в дашборде сервиса, необычные адресаты
SSH-ключПрямой доступ к серверуlast, auth.log, история команд, новые файлы в authorized_keys
Токен доступа к БДЧтение/запись данных напрямуюЛоги подключений СУБД, аномальные запросы, новые пользователи БД

Без этой таблицы (или её аналога под ваш стек) легко потратить время на проверку не той системы — например, искать следы в логах приложения, когда ключ давал доступ напрямую к облачному API в обход вашего кода.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Логи API и сервиса: ищем чужие вызовы этим ключом

Это основной источник доказательств — если он вообще существует. Смотрите не на сам секрет (он давно должен быть отозван и в логах может даже не отображаться в открытом виде), а на его идентификатор: у большинства ключей есть публичная часть или префикс, который отличает его от других, — AKIA... у AWS access key, key_id в логах API-шлюза, хеш или последние символы токена, которые вы сами логируете при выдаче.

В облачных провайдерах ищите по access key id в собственном журнале аудита. Для AWS это CloudTrail:

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIAXXXXXXXXXXXXXXXX \
  --start-time 2026-08-01T00:00:00Z \
  --end-time 2026-08-31T23:59:59Z

Смотрите не только на факт вызовов, но и на то, откуда они пришли: sourceIPAddress, регион, userAgent. Если весь легитимный трафик этим ключом шёл с известных IP вашей инфраструктуры (серверы деплоя, CI-раннеры), а в логе внезапно появился незнакомый диапазон — это прямой след.

В логах собственного API ищите по ключу так же, если вы его логируете (см. следующий раздел, почему это критично сделать заранее):

grep '"api_key_id":"kid_7f3a"' /var/log/app/access.log | \
  jq -r '[.ts, .ip, .method, .path, .status] | @tsv' | sort

Что считать подозрительным в этом выводе:

  • запросы к эндпоинтам, которые ваш код никогда не вызывает — если приложение только читает данные через GET /v1/orders, а в логе есть POST /v1/users или DELETE-запросы, это не ваш трафик;
  • источники за пределами вашей инфраструктуры — если известны все IP, с которых легитимно ходит этот ключ (сервер приложения, CI, конкретный офис), любой IP вне этого списка требует объяснения;
  • активность вне обычных временных окон — если ключ используется только во время деплоя раз в сутки, а в логе есть равномерный поток запросов ночью в выходной, это нехарактерно;
  • необычный User-Agent — ваш код обычно ходит через конкретный HTTP-клиент с предсказуемой сигнатурой; curl/8.x или Python-скрипт там, где обычно axios из вашего бэкенда, — повод присмотреться, хотя сам по себе это не доказательство: у легитимных запросов тоже бывают вариации.

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

Необычная активность в аккаунте помимо прямых вызовов

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

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

Изменённые настройки. Это менее очевидный, но важный след:

  • отключённые или изменённые алерты по биллингу — атакующий, который планирует использовать доступ долго, часто первым делом отключает то, что вас предупредит;
  • новые SSH-ключи в authorized_keys или новые ключи доступа, привязанные к аккаунту;
  • изменённые правила пересылки почты или новые webhook-эндпоинты — способ незаметно получать копию данных;
  • изменения в MFA — отключение второго фактора для аккаунта или сервисного пользователя.

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

Здесь же стоит свериться со связанными материалами: если утечка произошла через CI/CD, полезно посмотреть на разбор похожего инцидента с токеном, утёкшим в публичный репозиторий — там видно, как за считаные минуты сканер находит рабочий токен и что именно с ним успевают сделать.

Почему без логирования использования ключей заранее расследование почти невозможно

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

Это стоит исправить заранее, а не в момент инцидента:

  • включите детальные data events там, где провайдер это позволяет (CloudTrail для S3/Lambda и других сервисов данных — по умолчанию логируются только management-события, а не каждое обращение к объекту);
  • логируйте идентификатор ключа на уровне своего API, а не факт «был какой-то ключ». Пример конфигурации nginx с полем ключа в логе:
log_format api_access '$remote_addr - [$time_iso8601] '
                       'key="$http_x_api_key_id" '
                       '"$request" $status $body_bytes_sent '
                       '"$http_user_agent"';

access_log /var/log/nginx/api_access.log api_access;

Обратите внимание: в лог пишется $http_x_api_key_id — короткий публичный идентификатор ключа, который клиент передаёт отдельным заголовком, а не сам секрет и не его хеш в открытом виде. Если у вас сейчас в схеме API только один непрозрачный секрет без отдельного id, стоит на уровне приложения выдавать составные ключи вида id.secret — это стандартная практика у Stripe и похожих API, и она сама по себе облегчает будущее расследование;

  • настройте retention логов так, чтобы окно хранения было длиннее реалистичного окна между утечкой и обнаружением — если секрет может пролежать в старом коммите месяцами, а логи ротируются за неделю, доказать использование за пределами этой недели вы не сможете физически;
  • проверьте встроенный аудит-лог SaaS-сервисов, которыми пользуетесь: у GitHub, GitLab, Cloudflare, большинства платёжных и почтовых провайдеров есть панель audit log — включите её заранее и убедитесь, что доступ к ней есть у тех, кто будет разбирать инцидент, а не только у владельца аккаунта.

Про то, как выстроить сбор и хранение таких логов на собственном сервере системно, а не только для одного API, — в отдельном материале про настройку audit-логов через auditd.

Презумпция компрометации, когда однозначных доказательств нет

Итог расследования обычно один из трёх:

  1. Есть чёткие следы использования — совпадающие по времени, IP и типу операции с окном утечки. Тогда дальше это уже не вопрос «пользовались или нет», а полноценный разбор инцидента: что именно затронуто, кого уведомлять, какие ещё секреты могли быть скомпрометированы через полученный доступ.
  2. Есть чистый и полный лог за весь период риска, и в нём ничего подозрительного нет. Это достаточно надёжное основание считать, что использования не было — при условии, что логирование действительно покрывало весь период с момента появления секрета в открытом доступе до его отзыва, а не только последние несколько дней.
  3. Логов за нужный период нет или они неполные. Это самый частый и самый неприятный случай на практике — и именно тут проявляется разница между «доказали безопасность» и «не нашли доказательств проблемы», потому что это не одно и то же.

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

  • ротацию секрета в любом случае, даже если она уже произошла, — убедитесь, что отозван именно старый экземпляр, а не только выпущен новый;
  • расширенный период мониторинга после инцидента — несколько недель повышенного внимания к ресурсам и активности, которые были доступны по этому ключу;
  • по возможности запрос логов у провайдера — служба поддержки безопасности крупных облачных и SaaS-провайдеров иногда может поднять внутренние логи глубже, чем доступно в стандартной панели, особенно если формально описать инцидент;
  • честную оценку рисков для данных пользователей — если ключ мог дать доступ к персональным данным, а доказать обратное вы не можете, решение об уведомлении лучше принимать исходя из худшего правдоподобного сценария, а не из отсутствия улик. Общую последовательность действий при подозрении на взлом разбирали в материале про incident response plan.

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Секрет был виден в публичном репозитории всего пару часов. Можно не разбираться подробно?

Нет безопасного короткого окна — сканеры GitHub и подобных площадок находят токены за минуты. Проверьте логи за этот период по стандартной схеме; если логов нет, действует презумпция компрометации независимо от длительности окна.

Как отличить своих сотрудников от злоумышленника в логах, если оба заходят с похожих IP?

Сверяйте не только IP, но и паттерн действий: сотрудник обычно укладывается в свои обычные задачи, рабочее время и привычный клиент. Резкое расширение прав («вдруг создали нового администратора») или операция вне профиля роли — повод уточнить у сотрудника напрямую, прежде чем делать выводы по логам.

Что делать, если провайдер вообще не хранит логи использования API-ключей?

Такое встречается у небольших SaaS без встроенного аудита. Единственный практичный путь — презумпция компрометации: ротация ключа, смена связанных с ним данных (например, вебхук-эндпоинтов), и по возможности переход на сервис с журналом аудита для критичных интеграций.

Нужно ли уведомлять пользователей, если следов использования не нашли, но и логов за весь период не было?

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

Стоит ли включать полное логирование каждого вызова API постоянно, если это дорого по месту?

Необязательно логировать тело запроса — обычно достаточно строки с временем, идентификатором ключа, IP, эндпоинтом и статусом ответа. Это компактнее полного дампа и почти всегда хватает, чтобы восстановить картину использования при инциденте.

Обсудить статью, задать вопрос или начать новую тему

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

Перейти в сообщество →