API-ключ попал в JavaScript или репозиторий: что делать владельцу сайта
Если секретный API-ключ оказался в JavaScript сайта, публичном репозитории или доступном журнале, удаление строки из кода не прекращает доступ по этому ключу. Нужно определить, какие права раскрыты, отозвать скомпрометированный доступ у провайдера, перевести интеграцию на новые реквизиты и проверить последствия. Отдельная задача — устранить путь, по которому секрет попал наружу, чтобы следующая сборка не повторила ошибку.
Ниже — порядок действий для владельца сайта и разработчика. Он подходит для ключей CRM, платёжных, почтовых и других API, но конкретные кнопки отзыва и правила замены всегда нужно сверять с документацией своего сервиса. Сначала установите тип найденного значения: не любой идентификатор в браузере является секретом.
1. Определите, какой ключ оказался доступен
У разных API встречаются публичные идентификаторы, клиентские ключи с ограничениями, серверные секреты и ключи подписи уведомлений. Название переменной API_KEY не устанавливает её назначение. Найдите значение в панели соответствующего сервиса по безопасному идентификатору и проверьте тип, владельца, окружение, разрешённые операции и ограничения. Полный секрет не нужно копировать в задачу для подрядчика.
Например, Stripe различает publishable, restricted и secret API keys. Publishable key предназначен для клиентского кода, тогда как restricted key с ограниченными правами остаётся секретным. Это правила конкретного провайдера: похожее название или префикс у другого сервиса не гарантируют такое же назначение.
Если найденный ключ действительно разрешено публиковать, проверьте предусмотренные провайдером ограничения его использования. Если он позволяет выполнять серверные операции от имени магазина, относитесь к публикации как к раскрытию доступа. Отсутствие жалоб и неизвестность числа просмотров не делают секрет снова закрытым.
Отдельно различайте ключ тестовой среды и рабочего аккаунта. Тестовый секрет тоже требует защиты: он может открывать данные тестового проекта и влиять на проверку интеграции. Но его отзыв не должен случайно затронуть рабочий магазин с другим набором реквизитов.
2. Зафиксируйте границы утечки без распространения секрета
Создайте короткую карточку инцидента: где обнаружено значение, к какому сервису оно относится, кто отвечает за отзыв и какие части сайта используют этот доступ. Вместо секрета запишите его идентификатор из панели, название серверной настройки или внутренний псевдоним. Такой записи достаточно, чтобы разработчики обсуждали один объект.
| Что установить | Какое свидетельство сохранить |
|---|---|
| Место раскрытия | Путь к файлу, версия сборки или номер коммита без значения ключа |
| Время | Когда материал стал доступен и когда утечку обнаружили |
| Права | Аккаунт, окружение, разрешённые действия и объекты |
| Потребители | Сайт, фоновые задачи, интеграции и ответственные за переключение |
| Следующие шаги | Отзыв, восстановление работы, проверка обращений и устранение причины |
Время обнаружения не равно началу раскрытия. Если файл опубликован утром, а предупреждение пришло вечером, журнал нужно смотреть за весь установленный период. Когда начало неизвестно, обозначьте это явно и расширьте проверку по доступной истории публикаций. Не заменяйте неизвестную дату удобным предположением.
Ограничьте доступ к техническим материалам расследования. Для обычной рабочей переписки используйте обезличенные сведения; подробные журналы храните в согласованном защищённом месте. Не отправляйте найденный секрет в сторонний онлайн-проверяльщик и не вставляйте его в поисковую строку.
3. Отзовите раскрытый доступ у провайдера
Отзыв выполняют там, где ключ выдаётся и проверяется. Удаление переменной на хостинге, перевод репозитория в закрытый режим или очистка кеша сайта не являются отзывом. В рекомендациях OWASP по жизненному циклу секретов отзыв выделен как отдельный этап для больше не нужных или потенциально скомпрометированных реквизитов.
При подтверждённой утечке действуйте без ожидания доказательств злоупотребления. В частности, Stripe рекомендует немедленно ротировать раскрытый секретный или restricted key, даже если неизвестно, видел ли его кто-либо. Ротация должна закончиться прекращением действия старого значения; создание второго активного ключа само по себе этого не обеспечивает.
Если есть признаки посторонних обращений или ключ даёт широкие права, немедленно ограничьте раскрытый доступ и примите возможную временную остановку затронутой функции. Для плановой замены без инцидента провайдер может разрешать период совместной работы ключей, но оставлять раскрытый секрет действующим на длительное время ради удобства нельзя.
Проверьте результат в панели и зафиксируйте время отзыва. Если ключ позволял создавать другие реквизиты, токены или учётные записи, выясните у провайдера, что происходит с ними после отзыва исходного ключа. Не считайте автоматически закрытым любой доступ, когда-либо полученный с его помощью.
4. Переключите всех потребителей на новый ключ
Составьте список мест использования до объявления восстановления. Помимо основного сайта, это могут быть обработчик формы, очередь отправки писем, ночной обмен с CRM, задания cron и отдельный сервис выгрузки. Замена настройки только в веб-приложении оставит фоновые процессы со старым доступом.
Новый ключ создавайте для нужного аккаунта и окружения, предоставляя только необходимые права. Если выгрузке достаточно читать каталог, право изменять пользователей ей не требуется. Раздельные ключи для разных компонентов упрощают следующую замену и позволяют точнее установить, какая интеграция выполняла запросы.
Передавайте реквизиты через предусмотренные хостингом или инфраструктурой настройки секретов. В исходном коде должна остаться ссылка на настройку, а не её значение. После изменения выясните, когда каждый процесс читает конфигурацию: при запуске, при запросе или из собственного кеша. При необходимости выполните штатный перезапуск соответствующих воркеров и приложения.
Отмечайте каждого потребителя отдельно: настройка обновлена, процесс перечитал её, контрольная операция прошла. Для задачи, которая запускается раз в сутки, успешная работа главной страницы ничего не доказывает. Проверьте её на безопасном контрольном объекте либо дождитесь ближайшего запуска с ответственным за результат.
5. Уберите секрет из клиентской архитектуры
JavaScript, который получает браузер посетителя, нельзя использовать как закрытое хранилище. Минификация, переименование переменной и кодирование Base64 не изменяют эту границу: приложение должно восстановить значение, чтобы отправить запрос. Нельзя исправить утечку API-ключа в JavaScript, просто заменив старое значение новым в том же файле.
Переменная окружения также не гарантирует серверное хранение. Например, Vite включает значения переменных с префиксом VITE_ в клиентскую сборку. Поэтому перенос секрета из исходного файла в .env с таким префиксом сохраняет проблему. Проверять нужно итоговый путь значения до браузера, а не только место его первоначальной записи.
Если операция требует серверного секрета, выполняйте её на сервере. Браузер передаёт допустимые данные вашему обработчику, а тот проверяет пользователя или предусмотренные правила публичной формы, права на объект и параметры действия. Затем сервер обращается к внешнему API и возвращает клиенту только необходимый результат.
Не превращайте обработчик в свободный прокси, который по команде любого посетителя выполняет произвольные запросы с вашим ключом. Например, форма заявки может разрешать создание одной заявки с проверенными полями, но не выбор произвольного метода CRM и аккаунта назначения. Секрет скрыт от браузера, однако возможность использовать его полномочия тоже должна быть ограничена.
6. Проверьте репозиторий, историю и артефакты
Удаление строки новым коммитом убирает её из текущей версии, но прежняя версия может остаться в истории. В инструкции GitHub по удалению чувствительных данных первым действием для секрета указан отзыв или ротация. Очистка истории — отдельная согласованная операция с последствиями для копий репозитория и работы команды.
Не выполняйте переписывание всей истории наугад. Определите затронутые ветки, теги и артефакты, сохраните необходимые сведения расследования и согласуйте действия с разработчиками. Старые клоны и форки могут сохранить раскрытое значение; нельзя гарантировать удаление всех чужих копий. Именно поэтому прекращение действия ключа не заменяется очисткой Git.
Добавьте локальные файлы с секретами в правила исключений на будущее. При этом документация gitignore прямо указывает: правила не действуют на уже отслеживаемые файлы. Один новый пункт в .gitignore не удаляет ранее закоммиченный секрет и не исправляет опубликованную сборку.
Проверьте также архивы релизов, журналы сборки, вложения к задачам и сохранённые пакеты развёртывания. Для каждого места определите, можно ли убрать материал и кто имеет к нему доступ. Устраняйте раскрытие, сохраняя необходимые для расследования записи в защищённом виде.
7. Пересоберите сайт и проверьте опубликованную версию
Исправленный исходный код ещё не означает исправленный сайт. Соберите приложение с новой конфигурацией и проверьте именно файлы, которые будут доступны посетителю. Убедитесь, что секрет не попадает в JavaScript, HTML, начальные данные страницы, карты исходного кода или ответы вашего API.
При поиске ориентируйтесь не только на имя переменной: сборщик может заменить его готовым значением. Проверку выполняйте в контролируемой среде, не печатая секреты в общий журнал CI. В отчёте достаточно пути к файлу и результата проверки. Отсутствие известного имени переменной само по себе не доказывает отсутствия раскрытого значения.
После публикации проверьте реальный ответ сайта и CDN. Удалите ненужные доступные копии старых сборок, обновите ссылки на ресурсы и предусмотренный механизм кеширования. Если проект использует service worker, проверьте сценарий обновления уже установленного приложения. Очистка кеша только в браузере разработчика не подтверждает, что посетители получили новый выпуск.
Некоторые посетители могут сохранить старые файлы у себя. Работа с кешем помогает доставить исправление, но безопасность старого секрета обеспечивает его отзыв. При открытии устаревшей версии сайт должен предложить корректное восстановление интерфейса, а не бесконечно повторять недействующий запрос или создавать новые заказы.
8. Проверьте обращения и возможные последствия
После ограничения доступа сопоставьте журналы провайдера и своей интеграции за период раскрытия. Ищите обращения по идентификатору ключа, необычные методы, объекты, объём запросов и расход оплачиваемых ресурсов. Доступность таких полей зависит от сервиса; отсутствие нужной детализации следует указать в результате проверки.
Необычный IP-адрес не всегда означает постороннего: ваши запросы могут идти через облачный выходной адрес, прокси или новую площадку. Сравнивайте его с известной инфраструктурой, временем задач и назначением операции. И наоборот, привычный адрес не исключает злоупотребление через скомпрометированный компонент сайта.
Проверьте изменения, которые мог разрешать ключ: созданные или изменённые записи, отправленные сообщения, новые пользователи, настройки интеграции. Для платёжного сервиса изучайте объекты операций и их состояние; не выполняйте массовые отмены или возвраты только по предположению о компрометации. Сначала установите конкретное действие и его связь с инцидентом.
Если необходимы сведения, недоступные в панели, обращайтесь в поддержку провайдера через официальный канал. Передайте идентификатор ключа, аккаунт, временной интервал и обезличенные номера запросов. Не прикладывайте действующий секрет. Итог «в доступных журналах подозрительных операций не найдено» точнее, чем неподтверждённое «ключом точно никто не воспользовался».
9. Проверьте, где новый секрет хранится во время работы
Разделение кода и конфигурации помогает управлять ключами, но серверная настройка тоже нуждается в ограничении доступа. Проверьте, кто может читать её в панели хостинга, запускать задания с её использованием и просматривать диагностические данные. Подрядчику, который меняет оформление страницы, обычно не нужен рабочий ключ платёжного API.
На обычном хостинге используйте доступный защищённый механизм конфигурации и права файлов, соответствующие процессу приложения. Если применяется файл окружения, он не должен раздаваться веб-сервером как обычный документ. Проверяйте это для реального размещения сайта, включая резервные копии файлов и альтернативные расширения, которые создаёт редактор.
Отключите вывод секретов в сообщения об ошибках, отладочные страницы и общие логи. Не сохраняйте полный заголовок авторизации или содержимое всех переменных окружения ради диагностики одного сбоя. Для рабочих записей используйте название интеграции, идентификатор ключа и код результата, достаточные для поиска обращения.
Если утечка связана с доступом постороннего к серверу, аккаунту хостинга или системе сборки, простая замена значения внутри той же среды недостаточна. Сначала ограничьте источник такого доступа и организуйте восстановление с ответственным специалистом. Новый секрет должен попасть в среду, контроль над которой восстановлен.
10. Разберите учебный случай с формой заявки
Представим сайт, где браузер напрямую создавал заявку в CRM с серверным ключом из JavaScript. Владелец получил сообщение об утечке и попросил «заменить ключ в файле». Такая правка повторно раскроет доступ, поэтому решение должно изменить место выполнения операции.
Разработчик устанавливает, что ключ относится к рабочей CRM и используется ещё ночной выгрузкой. Ключ отзывают, а форму временно переводят в понятное состояние недоступности отправки. Интерфейс не показывает «Заявка принята», когда обработка остановлена. Уже сохранённые обращения остаются в учёте и не отправляются повторно без проверки.
Затем создают отдельные ограниченные реквизиты для серверного обработчика и выгрузки. Обработчик принимает только предусмотренные поля формы, проверяет их и вызывает CRM со своей серверной настройкой. После публикации проверяют создание одного тестового объекта и его ID, отсутствие секрета в ответах браузера и обновление фоновой задачи.
| Проверка | Критерий завершения |
|---|---|
| Раскрытый доступ | Старый ключ отозван у провайдера |
| Новая заявка | Один контрольный запрос связан с одним объектом CRM |
| Клиентские файлы | Новые серверные реквизиты не передаются посетителю |
| Ночная выгрузка | Использует отдельную обновлённую настройку и проходит проверку |
Это учебная модель, а не отчёт о конкретном инциденте. Она показывает, почему проверка только внешнего вида формы пропускает две проблемы: повторное раскрытие нового секрета и отказ отдельного фонового процесса.
11. Подтвердите восстановление положительными и отрицательными проверками
Положительная проверка отвечает на вопрос, выполняет ли новый доступ нужную операцию. Отрицательная — отклоняет ли система то, что больше не должно быть разрешено. Для отозванного ключа сначала используйте статус в панели провайдера. Если требуется дополнительный тест, выполняйте только документированное безопасное чтение в контролируемой среде, без передачи секрета в URL, общий терминальный журнал или сторонний инструмент.
Не проверяйте отзыв созданием настоящего платежа, удалением записи или рассылкой клиентам. Код ошибки может зависеть от API, поэтому ожидаемый отказ заранее определите по его документации. Один отказ из-за неверного адреса или отсутствующего объекта не доказывает, что ключ недействителен.
- Старый ключ имеет подтверждённый отозванный статус.
- Новый ключ относится к нужному аккаунту, окружению и набору прав.
- Основная функция и фоновые потребители работают с новой конфигурацией.
- Секрет отсутствует в материалах, которые получает посетитель сайта.
- Повторная публикация и перезапуск не возвращают старые настройки.
- Период раскрытия, проверенные журналы и оставшиеся неизвестные зафиксированы.
Назначьте ответственного за оставшиеся вопросы, если журналы ещё ожидаются от провайдера. Восстановление работы сайта и завершение расследования могут происходить в разное время; состояние каждой задачи должно быть видно отдельно.
12. Сделайте следующую замену управляемой
Ведите реестр интеграций без значений секретов: сервис, владелец, окружение, назначение ключа, потребители и порядок отзыва. Проверяйте этот список после подключения нового модуля или передачи проекта подрядчику. Он позволяет быстро найти ночную задачу, о которой не вспомнили во время срочной замены.
Добавьте проверку секретов в рабочий процесс. Например, secret scanning GitHub проверяет известные типы реквизитов в истории репозитория. Наличие сканера полезно, но его область проверки и поддерживаемые форматы нужно знать. Пользовательский ключ необычного формата и значение, добавленное только при сборке, требуют соответствующих проверок своего проекта.
Проверяйте итоговые артефакты, используйте учебные значения в документации и заранее отрабатывайте замену на тестовой интеграции. Критерий готовности — команда умеет найти потребителей, прекратить старый доступ и подтвердить работу нового без догадок о том, где хранится настройка.
Для внешнего наблюдения за HTTP-доступностью сайта подключите SiteGuard. После изменений проверяйте также саму интеграцию: отзыв ключей, права доступа и результат API-операций подтверждаются средствами вашего приложения и провайдера.