Секреты в коде сайта: как из-за них утекают данные и что проверить

3 сентября в сеть выложили 550 ГБ данных Manchester Airports Group. По заявлению атакующих, вход дали ключи администратора, лежавшие в JavaScript сайтов. Внутри: 6 мест, где секреты оказываются на виду, проверка своего сайта за 20 минут и порядок действий, если ключ нашелся.

550 ГБ данных, 8,8 млн адресов и телефонов, 108 тыс. автомобильных номеров. Точка входа, по заявлению взломщиков, — ключи администратора, лежавшие в JavaScript на главных страницах его сайтов.

Это история Manchester Airports Group, опубликованная SecurityWeek 3 сентября 2026 года. Масштаб тут вторичен. Интересна банальность причины. Секрет в коде фронтенда — это не экзотическая уязвимость и не нулевой день. Это обычная строчка, которую разработчик написал, чтобы «пока работало», и которая уехала в продакшен вместе со сборкой.

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

Что произошло в Манчестере

Manchester Airports Group управляет аэропортами Манчестера, Лондон-Станстеда и Ист-Мидлендса. В конце августа компания сообщила о взломе: похищены данные бронирований парковок, бизнес-залов и услуги Fast Track, а также регистрации в аэропортовом Wi-Fi. В утечку попали адреса электронной почты, телефоны, регистрационные номера автомобилей и почтовые индексы. Операционная деятельность аэропортов не пострадала.

MAG подтвердила 2 вещи: украденные данные хранились в базе, размещенной у стороннего подрядчика, и компания получила требование выкупа. Платить отказались. В первые выходные сентября группировка FulcrumSec взяла ответственность на себя и выложила примерно 550 ГБ данных.

Сервис Have I Been Pwned разобрал массив и добавил его в базу: около 8,8 млн адресов почты и телефонов, плюс имена, данные браузера, покупки и автомобильные номера. Сама группировка заявляет о 2 482 763 покупках, 461 433 SMS, привязанных к бронированиям, и 108 077 уникальных британских номерных знаков.

Способ проникновения FulcrumSec описывает буквально: административные ключи лежали «на виду, во фронтенд-JavaScript каждого из трех сайтов аэропортов», в корне каждого домена. Проверить это независимо SecurityWeek не смог: перед нами заявление атакующих, подтверждения расследованием пока нет. Но сам сценарий встречается регулярно, и именно он делает историю полезной.

Что считается секретом

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

Главное свойство секрета: он работает у любого, кто его держит. Сервис на другом конце не отличает запрос вашего сайта от запроса человека, скопировавшего ключ из исходников.

Отсюда правило, которое нарушают чаще всего. Все, что отдается браузеру, — публично. Минификация не прячет: строку видно поиском по файлу. Обфускация не прячет: ключ все равно должен быть в открытом виде в момент запроса. Переменная с именем window.__INTERNAL_KEY не становится внутренней оттого, что так названа.

Есть класс ключей, которые в браузере находиться обязаны: публичный ключ Яндекс Карт, идентификатор счетчика аналитики, публичный ключ платежной формы. Они и рассчитаны на публичность, у них урезаны права и обычно есть привязка к домену. Признак нормального публичного ключа простой: в документации вендора написано, что его можно размещать на странице, и он не умеет ничего, кроме чтения.

Бесплатный аудит вашего сайта
Найдем уязвимости и точки роста за 3 дня. Покажем, что чинить в первую очередь. Новым клиентам поддержки сайтов аудит делаем бесплатно.
Получить аудит

Где секреты оказываются на виду: 6 типовых мест

По нашей практике в проектах поддержки почти все находки укладываются в этот список.

Схема: 6 мест на сайте, где чаще всего находят открытые ключи и пароли
Секрет попадает в открытый доступ 6 типовыми путями. Первые 3 видны из браузера без всяких инструментов.
  • Сборка фронтенда. Современные сборщики подставляют переменные окружения в код на этапе сборки. Если переменная названа так, что попадает в публичный префикс, ее значение уезжает в бандл. Разработчик видит у себя .env, а пользователь — готовую строку в скачанном файле.
  • Инлайновый скрипт в шаблоне. Токен интеграции, вписанный прямо в <script> в шапке сайта, — классика при подключении сторонних сервисов на скорую руку.
  • Карты исходников. Файлы .map, выложенные рядом со сборкой, восстанавливают исходный код со всеми комментариями и именами переменных. Иногда там лежит то, чего нет в минифицированном виде.
  • Служебные файлы в корне сайта. .env, config.php.bak, dump.sql, папка .git. Ни один из них не должен отдаваться по HTTP, но веб-сервер по умолчанию отдает все, что лежит в его корне.
  • История репозитория. Ключ добавили, через день убрали, но коммит остался. Если репозиторий когда-либо был публичным или у него есть форки, ключ считается скомпрометированным навсегда.
  • Подрядчики и сторонние системы. В истории MAG база лежала у третьей стороны. Ваш ключ может утечь не через ваш сайт, а через сервис, которому вы его выдали.

Отдельная строчка про 1С-Битрикс. Параметры подключения к базе хранятся в /bitrix/php_interface/dbconn.php в версиях до 20.900.0 и в /bitrix/.settings.php начиная с нее. Опасны не сами файлы — PHP их не отдает, — а их копии: dbconn.php.bak, .settings.php.old, dbconn.txt. Расширение изменилось, и веб-сервер отдает содержимое как обычный текст.

Проверка своего сайта за 20 минут

3 действия, для которых не нужен ни пентест, ни специальные права.

Шаг 1. Посмотрите, что скачивает браузер. Откройте сайт, нажмите F12, вкладка Sources или Network. Скачайте главный JS-файл сборки и поищите по нему подстроки: secret, token, api_key, apiKey, password, Bearer, AKIA, sk_live, -----BEGIN. Находки читайте глазами: половина совпадений окажется именами полей без самих значений.

Шаг 2. Постучитесь в служебные файлы. Все они должны отвечать 403 или 404. Ответ 200 — это находка.

SITE=https://example.ru
for p in .env .env.local .git/config .git/HEAD config.php.bak \
         dump.sql backup.zip .settings.php.bak composer.lock \
         bitrix/php_interface/dbconn.php.bak; do
  code=$(curl -s -o /dev/null -w "%{http_code}" "$SITE/$p")
  echo "$code  $SITE/$p"
done

Шаг 3. Проверьте историю репозитория. Git умеет искать по содержимому всех коммитов, включая давно удаленные строки.

# Ищем строку во всей истории проекта
git log -p -S 'api_key' --all | head -n 60

# Список файлов, которые когда-либо назывались .env
git log --all --diff-filter=A --name-only --pretty=format: | sort -u | grep -E '\.env|\.pem|\.key$'

Если по итогам 3 шагов ничего не нашлось — это хороший результат, но не повод останавливаться: см. раздел про процесс ниже. Если нашлось — дальше по порядку.

Поддержка сайта на 1С-Битрикс
Возьмем ваш сайт на обслуживание: реакция от 15 минут, отчет по каждому часу, штатная команда вместо фриланса. Оценим объем работ до старта. Для сайтов на Битриксе — отдельный регламент обновлений и безопасности, для магазинов — поддержка интернет-магазинов.
Условия поддержки

Нашли ключ. Первые 2 часа

Порядок здесь важнее скорости, и первый шаг не тот, который просится.

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

Первое: отзовите и перевыпустите ключ. Не удаляйте строку из кода, не переписывайте историю коммитов, не думайте о том, кто виноват. Пока старый ключ действителен, все остальное бессмысленно. Ротация занимает минуты, и только она реально закрывает дыру.

Второе: посмотрите логи сервиса, к которому ключ давал доступ. Нужны нетипичные обращения: чужие IP, всплески запросов, выгрузки больших объемов, обращения ночью. Это единственный способ понять, воспользовались ключом или нет.

Третье: закройте саму причину. Ключ из браузера убирается не удалением строки, а переносом вызова на сервер: страница обращается к вашему же эндпоинту, а тот уже ходит во внешний сервис со своим ключом. Обычно это небольшая доработка сайта на несколько часов; переписывать фронтенд целиком не требуется.

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

Как закрыть это на уровне процесса

Разовая проверка ловит то, что уже есть. Чтобы не появлялось новое, нужны 4 вещи, и все они настраиваются за один день.

Запрет на отдачу служебных файлов веб-сервером. Базовая гигиена, которая закрывает сразу половину списка находок.

# Скрытые файлы и служебные расширения не отдаются никогда
location ~ /\.(env|git|svn|ht) { deny all; return 404; }
location ~* \.(bak|old|orig|sql|log|zip|tar|gz|sw[op])$ { deny all; return 404; }

Секреты вне корня сайта. Файл с паролями лежит уровнем выше public_html или передается через переменные окружения процесса. Внутри репозитория — только шаблон .env.example с пустыми значениями.

Автоматическая проверка на стороне репозитория. У GitHub есть защита пуша: сканер распознает известные форматы токенов и блокирует отправку, а для публичных репозиториев она включена по умолчанию. У нее есть ограничение, о котором честно написано в документации: она не спасает, если приватный репозиторий делают публичным.

Разделение прав и срок жизни. Ключ, который умеет только читать каталог, при утечке стоит несравнимо дешевле ключа с правом списания денег. Плановая ротация раз в квартал делает украденный полгода назад токен бесполезным. В Design Lab проверка отдачи служебных файлов и поиск строк-секретов в бандле входят в чек-лист приемки сайта на поддержку — это 15 минут работы, которые регулярно что-нибудь находят.

Что требует закон, если данные все-таки утекли

Для российского оператора персональных данных сроки жесткие. По части 3.1 статьи 21 закона 152-ФЗ оператор обязан в течение 24 часов уведомить уполномоченный орган о произошедшем инциденте, его предполагаемых причинах и принятых мерах, а в течение 72 часов — сообщить результаты внутреннего расследования.

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

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

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

Мой сайт маленький, кому он нужен?

Открытые ключи находят не адресным взломом, а массовым сканированием: боты перебирают типовые пути вроде /.env по всем доменам подряд. Размер бизнеса тут не имеет значения, значение имеет только код ответа сервера. Логи любого сайта показывают такие запросы ежедневно.

Если ключ лежит в приватном репозитории, это безопасно?

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

Чем отличается публичный ключ карт от секретного токена?

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

Мы нашли ключ, но им явно никто не пользовался. Можно оставить?

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

Как часто нужно перепроверять сайт?

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

Что сделать сегодня

Откройте свой сайт, скачайте главный файл сборки и поищите в нем 5 слов из шага 1. Прогоните скрипт из шага 2 по служебным путям. На это уйдет меньше получаса, и в половине случаев результат будет скучным — это лучший из возможных исходов.

История MAG стоила компании 550 ГБ опубликованных данных и 8,8 млн пострадавших записей. Причиной, по заявлению атакующих, была строка в файле, который сайт сам отдавал каждому посетителю.

Бесплатный аудит вашего сайта
Найдем уязвимости и точки роста за 3 дня. Покажем, что чинить в первую очередь. Новым клиентам поддержки сайтов аудит делаем бесплатно.
Получить аудит
Давайте
обсудим проект
  • Разберем задачу и предложим решения
  • Покажем кейсы из вашей отрасли
  • Оценим сроки и бюджет до старта
Алексей Грицук
Алексей Грицук, руководитель
Что вас интересует?
Приложить файлы
Как с вами связаться?
Заявка отправлена!
Спасибо! Ответим в течение рабочего дня — тем способом, который вы выбрали.
Обсудить проект