Что проверить на сайте перед запуском
До запуска сайт месяцами живёт как тестовый стенд: закрытый, удобный для разработчиков и никому снаружи не интересный. В день запуска стенд не исчезает — он просто становится публичным, вместе со всеми своими привычками.
Стенд не исчезает — он становится публичным
До запуска сайт живёт удобной жизнью тестового стенда: админка на стандартном адресе, потому что так быстрее; шрифты с чужого CDN, потому что так было в туториале; капча «прикрутим потом», потому что форму всё равно заполняют только свои. Ничто из этого не проблема — ровно до дня, когда стенд объявляют боевым сайтом.
Коварство в том, что в день запуска ничего не ломается. Сайт открывается, формы отправляются, платежи проходят. Привычки стенда не мешают работать — они просто становятся видны всему интернету, и первыми их замечают не клиенты, а боты.
Ниже — девять следов тестовой жизни, которые чаще всего уезжают в прод, с симптомом и командой для проверки. Команды рассчитаны на терминал Linux или macOS; в Windows их выполнит WSL или Git Bash. Если вы не запускаетесь, а переезжаете на другой хостинг — это отдельный сюжет, и для него есть отдельный разбор.
1. Тестовые поддомены знают о вас больше, чем главная
Симптом: staging.example.ru открывается любому желающему — со старым кодом, тестовыми данными и админкой без пароля.
Кажется, что тестовый поддомен спрятан: ссылок на него нет, в поиске его нет, адрес знают трое. На деле его имя опубликовано в тот момент, когда на него выпустили сертификат: каждый выпущенный сертификат попадает в открытые журналы Certificate Transparency, и они доступны всем — в том числе тем, кто целенаправленно ищет чужие стенды. Прятать поддомен бессмысленно, его можно только закрыть.
curl -s "https://crt.sh/?q=%25.example.ru&output=json" \
| grep -oE '"common_name":"[^"]+"' | sort -u | head -n 20Ищите в списке dev, staging, test, qa, demo, beta — всё, что не должно быть публичным. Такие окружения обычно защищены хуже боевого: на них редко ставят актуальные обновления и почти никогда не смотрят логи. Правильное состояние тестового стенда — за аутентификацией, списком IP или VPN; выключенный стенд тоже вариант, но тогда снимите с него DNS-запись, чтобы адрес не достался чужому серверу.
2. Админка живёт на /admin, потому что так было удобно
Симптом: страница входа в админку открывается у любого посетителя по адресу, который угадывается с первой попытки.
На стенде стандартный адрес админки был удобен: не надо запоминать, не надо объяснять коллегам. В проде те же свойства работают против вас: боты обходят стандартные пути входа круглосуточно — /admin, /admin/login, /administrator у Joomla, /user/login у Drupal, /bitrix/admin/ у Битрикса, /wp-login.php у WordPress. Открытая страница входа — это не взлом, но это постоянный перебор паролей, и однажды он совпадёт.
curl -s -o /dev/null -w '%{http_code} %{url_effective}\n' -L https://example.ru/admin
curl -s -o /dev/null -w '%{http_code} %{url_effective}\n' -L https://example.ru/wp-login.phpВажная оговорка: код 200 сам по себе ничего не доказывает. Одностраничное приложение отвечает 200 на любой путь, отдавая одну и ту же оболочку. Мы считаем админку найденной, только если по адресу отвечает отдельная страница с формой входа — иначе ложная тревога случалась бы на каждом втором современном сайте.
Что делать: закрыть страницу входа списком IP или вторым фактором. Перенос на нестандартный адрес защитой не является, но срезает почти весь автоматический перебор.
3. Сайт сам называет свою CMS и её версию
Симптом: в коде страницы — тег <meta name="generator" content="WordPress 6.2">, поставленный движком из коробки.
Под каждую версию каждой популярной CMS существует публичный список известных уязвимостей. Боты не изучают ваш сайт — они ищут по всему интернету сайты с конкретной версией, под которую у них готов эксплойт. Тег generator избавляет их от необходимости угадывать: сайт сам сообщает, чем его атаковать. Это самая серьёзная находка из всего списка — и одна из самых дешёвых в исправлении.
curl -s https://example.ru | grep -io ']*>'Пустой вывод — правильный ответ. Если тег есть, уберите его в настройках или шаблоне движка; для WordPress это одна строка в functions.php. И это не отменяет главного: версию нужно не прятать, а обновлять — тег лишь делает устаревшую версию удобной мишенью.
4. Формы, которым на стенде никто не писал
Симптом: через неделю после запуска в почте — сотни заявок от «клиентов» с адресами вида qwe@qwe.com.
На стенде форму обратной связи заполняли только свои, и защита от ботов казалась лишней возней. Боты находят открытую форму быстрее первых клиентов — и дальше через неё идут спам, перебор и нагрузка на почту, среди которой легко потерять настоящую заявку. Лечится это капчей — Yandex SmartCaptcha, reCAPTCHA, Turnstile — и ограничением частоты отправок.
Вторая, более серьёзная привычка стенда — атрибут action, указывающий на http://-адрес. Всё, что посетитель вводит в такую форму — телефон, пароль, данные карты, — уходит по сети открытым текстом: это видит провайдер, владелец Wi-Fi в кафе и любой узел на пути. Для персональных данных это ещё и прямое невыполнение требования 152-ФЗ защищать их при передаче.
curl -s https://example.ru | grep -ioE 'В выводе не должно быть action="http://…" — только относительные пути или https://.
5. Шрифты с чужого CDN стали трансграничной передачей
Симптом: страница тянет ресурсы с fonts.gstatic.com, unpkg.com, jsdelivr.net — так было быстрее на этапе вёрстки.
Каждый внешний хост на странице — это запрос, который браузер посетителя делает напрямую, отдавая этому хосту свой IP-адрес. IP — персональные данные, а передача их на зарубежный сервер — то, что 152-ФЗ называет трансграничной передачей. Про счётчики аналитики это обычно помнят; про то, что шрифт, иконки и подключённая с CDN библиотека работают ровно так же, — почти никогда.
curl -s https://example.ru \
| grep -oE '(src|href)="https?://[^"]+"' | cut -d'"' -f2 \
| awk -F/ '{print $3}' | grep -v example.ru | sort -uКаждый хост в этом списке должен быть осознанным решением, а не привычкой стенда. Шрифты, стили и библиотеки дешевле всего забрать к себе — заодно страница перестанет зависеть от доступности чужого CDN. Виджеты и счётчики — либо российские аналоги, либо подключение после согласия посетителя.
6. Политика и согласие — последние в очереди на запуск
Симптом: форма собирает телефон и почту, а политики обработки персональных данных на сайте нет — «юрист пришлёт после запуска».
Обязанность опубликовать политику возникает не с первого клиента, а с первой формы: как только сайт собирает персональные данные, документ должен быть доступен посетителю. Рядом второй пункт — согласие на обработку берётся в момент сбора, то есть чекбоксом у самой формы, а не абзацем в глубине сайта. Нарушение — статья 13.11 КоАП, и проверку запускает не плановый обход, а одна жалоба одного посетителя.
curl -s https://example.ru | grep -ic 'персональных данных'Ноль в выводе — плохой знак: на странице с формой должны быть и ссылка на политику, и текст согласия. Оговорка в другую сторону: если согласие дорисовывает скрипт после загрузки страницы, снаружи его не видно — и наша проверка, и такой grep смотрят на исходный HTML, поэтому динамический чекбокс останется незамеченным. Убедитесь глазами, что он есть.
7. Сайт всё ещё закрыт от поиска — или открыт, но молчит
Симптом: запустились месяц назад, поискового трафика — ноль.
Стенд закрывали от индексации сознательно — тегом noindex или заголовком X-Robots-Tag, — и это была правильная настройка. Неправильно одно: о ней забыли в день запуска. Сайт при этом выглядит совершенно здоровым, и отсутствие себя в поиске замечают через месяц, по нулевому трафику.
curl -sI https://example.ru | grep -i x-robots-tag
curl -s https://example.ru | grep -io ']*>'Честная оговорка: это единственный пункт списка, который наша проверка за вас не сделает — запрет индексации мы не ищем, поэтому выполните эти две команды сами. Пустой вывод или index, follow — правильный ответ.
Обратная сторона той же настройки: сайт открыт, но поисковику не сказали, что индексировать. Проверьте, что robots.txt объявляет карту сайта строкой Sitemap: и что по этому адресу действительно отвечает файл, а не заглушка стенда.
8. TLS, каким его поставил образ из туториала
Симптом: сайт работает по HTTPS, но конфигурацию TLS никто не открывал с момента «скопировал из туториала — заработало».
Дефолт старого туториала или дистрибутива — это в лучшем случае TLS 1.2 без TLS 1.3: не проблема, но упущенные скорость и строгость — TLS 1.3 убирает устаревшие шифры и ускоряет рукопожатие. В худшем случае сервер согласует только действительно устаревшие наборы — CBC и статический RSA без прямой секретности. Разница не академическая: без прямой секретности записанный сегодня трафик можно расшифровать потом, если ключ сервера когда-нибудь утечёт.
openssl s_client -connect example.ru:443 -tls1_3 /dev/null \
| grep -E 'Protocol|Cipher'Пустой вывод означает, что TLS 1.3 сервер не поддерживает. Включается он одной строкой в конфигурации веб-сервера или в панели CDN — перед запуском это самая дешёвая из настроек с постоянным эффектом.
9. Витрина: как сайт выглядит в репостах, для исследователей и ассистентов
Симптом: первую же ссылку на сайт кто-то отправляет в мессенджер — и превью показывает пустой прямоугольник без названия и картинки.
Три маленьких файла и одна группа тегов решают, как сайт выглядит за его пределами. Open Graph и Twitter-теги — og:title, og:image, description — собирают карточку ссылки в мессенджерах и соцсетях; без них репост выглядит как спам. Файл /.well-known/security.txt со строкой Contact: даёт исследователю безопасности адрес, куда сообщить об уязвимости, — иначе он напишет в общую почту, и письмо утонет.
Третий пункт пока экзотика, но спрашивать о нём начнут раньше, чем кажется: /llms.txt — текстовое описание сайта для ИИ-ассистентов. Когда ChatGPT, Алису или Claude спросят про вашу компанию, пересказывать они будут то, что сумели понять; короткий файл с фактами о вас — способ поучаствовать в этом пересказе. Заодно решите осознанно, что разрешать ИИ-краулерам в robots.txt.
curl -s https://example.ru | grep -io 'og:[a-z:]*' | sort -u
curl -s https://example.ru/.well-known/security.txt
curl -s https://example.ru/llms.txt | head -n 5Чек-лист
| Что | Признак, что всё в порядке |
|---|---|
| Тестовые поддомены | Закрыты аутентификацией, списком IP или VPN |
| Страница входа в админку | Недоступна с произвольного адреса без второго фактора |
| Тег generator | Убран; версия CMS в коде страницы не видна |
| Формы | С капчей, action только на HTTPS |
| Внешние ресурсы | Список пересчитан; шрифты и библиотеки у себя |
| Политика и согласие | Политика опубликована, согласие — чекбоксом у формы |
| Индексация | noindex снят, Sitemap: объявлен в robots.txt |
| TLS | Сервер согласует TLS 1.3 |
| Витрина | OG-теги, security.txt и llms.txt на месте |
Чего такая проверка не покажет
Всё перечисленное — то, что сайт рассказывает о себе сам: HTML главной страницы, публичные журналы сертификатов, ответы стандартных адресов. Пассивная проверка этим и ограничена, и честнее сказать заранее, чего в ней нет.
Она не найдёт забытый каталог .git или дамп базы в корне — для этого нужен перебор путей, а это уже не наблюдение, а попытка что-то нащупать. Не найдёт уязвимости в коде и плагинах и не проверит то, что дорисовывает скрипт после загрузки страницы: динамический баннер cookie или чекбокс согласия останутся за кадром. Журналы сертификатов покажут только поддомены, на которые когда-либо выпускался сертификат, — стенд на голом IP в них не значится. И запрет индексации, как сказано выше, проверяется руками.
Зато всё, что видно снаружи, видно и тем, кто ищет лёгкие цели, — а свежезапущенный сайт они проверяют в первые же дни, пока привычки стенда ещё на месте.