2 августа 2026·Чтение 10 минут Разбор
Из открытого наружу сервера утекают ключи и файлы исходного кода, рядом — знак предупреждения

Открытый .git на сайте и забытый .env: как исходный код утекает наружу

Это не экзотика и не сложная атака. Сайт работает, ничего не сломано, а по адресу ваш-сайт.ру/.git/config браузер спокойно показывает текст — и вместе с ним наружу уходит исходный код проекта и вся история его правок. Разберём, откуда это берётся, чем на самом деле опасно и как закрыть за один вечер.

Что такое каталог .git и почему он оказался на сервере

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

На боевом сервере ему делать нечего, и всё же он там регулярно оказывается. Причины однотипные и скучные:

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

Почему это опаснее, чем «ну увидят исходники»

Первая реакция владельца обычно спокойная: «Ну и что, там нет ничего секретного, обычный сайт на PHP». Проблема в том, что открытый .git — это не «посмотреть пару файлов». Это доступ к архиву проекта, из которого восстанавливается рабочий исходный код целиком, а вместе с ним — вся история изменений.

Что из этого следует практически:

Ключевая мысль: удалить пароль из файла — не значит удалить его из истории

Git устроен так: каждое сохранение (коммит) фиксирует состояние файлов на тот момент и хранит его навсегда. Новый коммит не переписывает старый, а добавляется рядом. История — это не журнал изменений, это набор полных снимков.

Отсюда типичная история, которая происходила почти в каждом проекте:

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

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

Простая аналогия: вы отдали в архив договор с указанной суммой, а через неделю принесли исправленную версию без суммы. Первый экземпляр из архива при этом никто не изъял. Git работает ровно так же — новая версия дописывается, старая остаётся.

Именно поэтому открытый .git опасен даже на сайте-визитке, где «нечего красть»: интересен не текущий код, а то, что в этом коде когда-то лежало и было забыто.

Что обычно лежит рядом

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

ФайлЧто в нёмЧем грозит
.env пароль базы, ключи платёжного шлюза, токены рассылок, секрет сессий самый тяжёлый случай: доступы отдаются готовым списком, без всякого восстановления кода
dump.sql, backup.zip, site.tar.gz выгрузка базы или архив сайта, забытые в корне после переноса клиентская база, заказы, хеши паролей пользователей — скачиваются одним запросом
.svn то же, что .git, но от системы Subversion встречается на старых сайтах и проверяется злоумышленниками так же автоматически
composer.lock, package.json полный список библиотек с точными версиями сам по себе не уязвимость, но избавляет атакующего от подбора: видно, что устарело
.idea/, .vscode/, .DS_Store настройки редактора, иногда параметры подключения к серверам; .DS_Store — перечень файлов в папке раскрывает внутреннюю структуру проекта и служебные пути
phpinfo.php, test.php, info.php полная конфигурация PHP: версии, пути, модули, иногда переменные окружения оставляют «на пять минут» при отладке и забывают на годы

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

Как проверить у себя за минуту

Инструменты не нужны, достаточно браузера. Откройте по очереди (подставив свой домен):

  1. ваш-сайт.ру/.git/config
  2. ваш-сайт.ру/.env
  3. ваш-сайт.ру/dump.sql и ваш-сайт.ру/backup.zip
  4. ваш-сайт.ру/phpinfo.php

Что означает ответ:

Что вы увиделиЧто это значит
Текст файла или предложение скачать его Плохо. Файл доступен всему интернету прямо сейчас. Переходите к разделу «Как закрыть», а если это .git или .env — потом обязательно к разделу про перевыпуск секретов.
403 Forbidden Доступ закрыт — уже неплохо, но повод посмотреть настройку. Ответ 403 подтверждает, что файл существует, и часто означает, что закрыт только он, а не весь каталог. Проверьте заодно /.git/HEAD и /.git/index: бывает, что закрыли одно, а рядом всё открыто.
404 Not Found или обычная страница ошибки сайта Нормально. Либо файла нет, либо сервер настроен отдавать 404 на такие запросы — это и есть желаемое поведение.
Проверяйте так только свой сайт. Открыть эти адреса у чужого ресурса, а тем более выгрузить оттуда репозиторий — это уже не исследование, а неправомерный доступ к компьютерной информации со всеми вытекающими. Если заметили проблему у знакомых — напишите им, а не «проверьте подробнее».

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

Как закрыть

nginx

В блок server { ... } добавляется правило, запрещающее выдачу всего, что начинается с точки:

location ~ /\.(?!well-known) {
    deny all;
}

Оно закрывает разом .git, .env, .svn, .idea и любые другие скрытые файлы и каталоги.

Исключение .well-known убирать нельзя. Каталог /.well-known/ тоже начинается с точки, но он служебный и публичный: через него Let’s Encrypt подтверждает, что домен ваш, когда выпускает и продлевает бесплатный TLS-сертификат. Если закрыть скрытые файлы «все подряд», сертификат перестанет продлеваться — и месяца через три сайт встретит посетителей предупреждением браузера о небезопасном соединении. Конструкция (?!well-known) в правиле означает ровно одно: «всё, что с точки, кроме well-known».

Пара практических замечаний:

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

location ~* \.(sql|zip|tar|gz|bak|old)$ {
    return 404;
}

Перед добавлением убедитесь, что сайт не раздаёт такие файлы легально: если у вас есть раздел с загрузкой прайса в .zip, он перестанет работать. Правильнее вообще не хранить дампы и архивы внутри публичной папки — переложите их уровнем выше.

Apache

Для Apache 2.4 достаточно одной строки в файле .htaccess в корне сайта (создайте его, если файла нет):

RedirectMatch 404 /\.(?!well-known)

Логика та же: любой адрес, содержащий скрытый файл или каталог, получает 404, а .well-known продолжает работать. Резервные копии закрываются отдельно:

<FilesMatch "\.(sql|zip|tar|gz|bak|old)$">
    Require all denied
</FilesMatch>

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

Правильный вариант: не выкладывать служебные каталоги вообще

Правило в конфиге — это страховка, а не решение. Решение — чтобы .git и .env физически не лежали в публичной части сайта:

Если каталог был открыт: закрыть доступ — это только половина

Самая частая и самая дорогая ошибка на этом шаге — остановиться. «Правило добавили, теперь 404, вопрос решён». Не решён.

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

Все секреты, которые лежали в коде и в истории, считаются скомпрометированными и подлежат перевыпуску. Практический список:

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

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

Как не допустить повторения

  1. Внесите .env и подобные файлы в .gitignore — тогда они физически не попадут в репозиторий. Рядом держите .env.example с теми же именами настроек, но с пустыми значениями: новый разработчик поймёт, что нужно заполнить, а секрета в истории не появится.
  2. Секреты — в переменных окружения или в хранилище хостинга, не в файлах кода. Правило простое: если значение нельзя показать постороннему, оно не должно попадать в репозиторий даже на минуту.
  3. Разные ключи для тестовой и боевой среды. Тестовый контур почти всегда защищён хуже, и именно из него ключи утекают чаще. Если ключи одинаковые, утечка из теста — это утечка с боевого сайта.
  4. Проверяйте после каждого переезда и каждой выкладки вручную. Смена хостинга, подрядчика, перенос на новый сервер — три ситуации, в которых .git возвращается на место чаще всего. Проверка занимает минуту.
  5. Поставьте регулярную внешнюю проверку. Ручная проверка хороша ровно один раз: она ничего не скажет о файле, который появится в корне через полгода после спешного релиза в пятницу. Смысл имеет только повторяющийся контроль.
  6. Если один такой файл нашёлся — ищите остальные. Причина у них общая, поэтому по одному они встречаются редко.

Проверьте свой сайт бесплатно

ShieldSafe ищет открытые снаружи служебные файлы — .git, .env, забытые дампы и отладочные страницы, — а также известные уязвимости в используемых версиях компонентов. Каждая находка объясняется простым языком, с готовой формулировкой для разработчика. Устанавливать на сервер ничего не нужно.

Запустить проверку