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

Страницу тогда выключили, а запись в DNS осталась. За три года она пережила и акцию, и сам сервис, на который указывала, - и в какой-то момент начала отправлять посетителей на чужой сайт. Такие записи называют висячими, и в зоне любой компании, которая живёт дольше пары лет, их обычно несколько десятков.

Как получается висячая запись

Разберём тот же случай по шагам. Маркетингу нужна промо-страница, и её кладут не к себе, а на внешний хостинг: статические страницы в объектном хранилище, GitHub Pages, конструктор сайтов. У всех у них одна модель - вы придумываете имя проекта, и хостинг отдаёт вам адрес вида имя-проекта.хостинг.com. Имя выдаётся по принципу «кто первый занял», как никнейм.

Чтобы страница открывалась на своём домене, в зоне компании заводят запись, которая перенаправляет на этот адрес:

promo    CNAME    company-promo-2023.<хостинг>.

Акция кончается. Проект на хостинге удаляют - счёт закрыт, задача закрыта. В зону никто не заглядывает, потому что DNS ведёт другая команда, а тикета на удаление никто не заводил.

Имя проекта company-promo-2023 на стороне хостинга освободилось. Оно снова доступно для регистрации - любому. А запись в вашей зоне продолжает всех туда отправлять.

Тот, кто зарегистрирует это имя, начнёт отдавать собственный контент с адреса promo.example.com. И это не домен, похожий на ваш, а ваш собственный: сертификат выпишется автоматически, в адресной строке будет ваше имя, замочек будет на месте.

Почему это не ловится обычным мониторингом

Мониторинг доступности проверяет сайты, которые вы знаете. Висячая запись - по определению та, про которую забыли, её нет ни в одном списке.

Проверка «а резолвится ли имя» тоже не помогает - и вот здесь главная ловушка. Возьмём заведомо несуществующий проект на GitHub Pages и запросим у DNS его адреса:

$ dig +short nonexistent-abc123.github.io
185.199.109.153
185.199.111.153
185.199.110.153
185.199.108.153

Четыре адреса, всё в порядке. Только проекта с таким именем не существует - я его выдумал.

Так происходит потому, что у хостинга в DNS стоит запись-джокер на *.github.io: она отвечает на любое имя в этой зоне, независимо от того, зарегистрировано оно или нет. DNS отвечает за имена, а не за содержимое, и сведений о том, занят ли проект, в нём нет.

Значит, проверка на уровне DNS даёт одинаковое «да» и для рабочего сервиса, и для пустого места. Разница появляется, только когда вы запросите по этому адресу саму страницу:

$ curl -s -o /dev/null -w "%{http_code}\n" http://nonexistent-abc123.github.io/
404
$ curl -s http://nonexistent-abc123.github.io/ | grep -o '<title>.*</title>'
<title>Site not found &middot; GitHub Pages</title>

То же самое у объектного хранилища, только ответ приходит в XML:

$ curl -s http://nosuchbucket-abc123.s3.amazonaws.com/
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>NoSuchBucket</Code><Message>The specified bucket does not exist</Message>
<BucketName>nosuchbucket-abc123</BucketName>...

Site not found и NoSuchBucket - это и есть признак свободного имени: хостинг прямо говорит, что проекта у него нет, а ваша запись в DNS продолжает на него указывать. У большинства крупных сервисов такая страница своя и узнаваемая; если её нет, придётся сравнивать ответ с ответом на заведомо выдуманное имя того же хостинга.

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

Чем это оборачивается

Возражение здесь понятное: промо-страница трёхлетней давности никому не нужна, кому она навредит. Но ущерб не в странице, а в имени, под которым она теперь отдаётся.

Cookie домена. Если приложение выставляет cookie на .example.com - а так делают, чтобы одна авторизация работала на всех поддоменах, - то страница на promo.example.com эти cookie получит. Браузер отработает штатно: область действия задали вы сами, и он приложит cookie к запросу на любой поддомен внутри неё. Дальше их прочитает тот, кто этим поддоменом управляет. HttpOnly тут не помогает: читать cookie из JavaScript и не требуется, достаточно того, что браузер отправил их на сервер. Secure к этой ситуации отношения не имеет вовсе - он ограничивает только передачу по HTTPS. Помогает префикс __Host-: он привязывает cookie к конкретному хосту. Цена - та самая единая авторизация на всех поддоменах, ради которой cookie и ставили на весь домен; выбирать приходится между удобством и этим риском.

Доверие к домену. Ссылка на promo.example.com в письме проходит и почтовый шлюз, и глаза самого получателя: домен-то родной. Все советы вида «смотрите на адрес» здесь работают против защищающегося.

Списки разрешённых источников. Ваш собственный поддомен часто оказывается в Content-Security-Policy, в Access-Control-Allow-Origin, в правилах прокси, в списке разрешённых redirect_uri у OAuth-клиента. Все эти списки писались, когда поддомен был ваш.

Подтверждение владения. Часть сервисов принимает подтверждение по файлу на конкретном хосте - и если этот хост попал в чужие руки, подтверждение получит тот, кто им управляет.

Откуда берётся зона, которую никто не помнит

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

DNS-запись живёт дольше проекта, потому что её удаление никогда не входит в чек-лист закрытия. Открытие - входит: без записи ничего не заработает, про неё вспомнят обязательно.

Записи заводят несколько команд, а зона одна. Инфраструктура, разработка, маркетинг, внешнее агентство - у каждого свои поддомены, общего реестра нет ни у кого.

Автоматика создаёт записи под каждую ветку и окружение. Часть контуров при этом выведена из-под автоматики «потому что там что-то важное», и записи от них удаляют руками - то есть не удаляют.

Компанию купили вместе с её зоной. Что там было - не знает уже никто.

Как это чинится

Взять зону целиком. Не по памяти, а выгрузкой у DNS-провайдера через его API или панель. Если зон несколько - все, включая те, что на почтовом провайдере и у регистратора отдельно.

Разметить владельцев. Каждая запись получает две пометки: команду-владельца и причину существования. Форма годится любая - комментарий в описании записи у провайдера, отдельная таблица, поле в системе, откуда зона разворачивается кодом; важно, чтобы пометка жила рядом с записью и обновлялась вместе с ней. Всё, для чего владельца не нашлось, идёт в отдельный список - с ним и работаем.

Проверить, куда указывает каждая запись. Для CNAME - существует ли на той стороне проект с таким именем: смотреть надо на ответ приложения, а не на факт резолва. Для A и AAAA - принадлежит ли ещё адрес вам; облачные адреса возвращаются в общий пул и достаются следующему арендатору, и это обычная штатная механика, а не сбой.

Удалять, а не «оставить на всякий случай». С формулировки «вдруг понадобится» вся история и начинается заново. Понадобится - заведут заново, это одна запись.

Закрыть источник. Удаление записи вносится в процедуру вывода сервиса из эксплуатации, рядом с отзывом сертификата и закрытием доступов. Без этого через год список соберётся снова, и вы будете разбирать его с нуля.

Что посмотреть у себя

Выгрузить зону и посчитать записи. В моей практике расхождение с тем, что называют по памяти, получается в разы - этого одного обычно достаточно, чтобы разговор про инвентаризацию перестал быть теоретическим.

Отобрать все CNAME, ведущие на внешние домены. Это группа с наибольшим риском: имя проекта на той стороне может освободиться и достаться кому-то другому. Для каждого проверить ответ сервиса, а не факт резолва.

Посмотреть, на какой домен приложение выставляет cookie. Если на .example.com, а не на конкретный хост - цена висячей записи вырастает, и разбор списка становится срочным.

И отдельно - посмотреть логи Certificate Transparency по своему домену: проще всего через поиск на crt.sh по маске %.example.com или через API любого монитора CT. Там перечислены все имена, для которых кто-либо когда-либо выписывал сертификат, - включая те, что выписывали не вы. Часть этих имён вы не найдёте ни в одном своём списке.

Комментарии (8)


  1. HomeMan
    04.09.2026 15:24

    это не домен, похожий на ваш, а ваш собственный: сертификат выпишется автоматически, в адресной строке будет ваше имя, замочек будет на месте.

    Это же про продление сертификатов хостингом?

    Сертификатами лучше управлять самому.

    Проблем меньше.


    1. jbenderov Автор
      04.09.2026 15:24

      Сертификат здесь — всего лишь следствие, а не причина. Если вы управляете сертификатами сами, но оставляете «висячий» CNAME, злоумышленник всё равно получит ваш домен и автоматически выпустит на него свой сертификат (через Let's Encrypt или другого провайдера).

      Ваше собственное управление сертификатами эту атаку не закрывает, потому что вы не контролируете, кто запрашивает сертификат для вашего поддомена, пока DNS указывает на чужой IP.


      1. HomeMan
        04.09.2026 15:24

        т.е. они забили кол даже на ДНС?

        Ну что могло пойти не так.


  1. dinar_007
    04.09.2026 15:24

    Я бы ещё в процедуре выключения жёстко зафиксировал порядок: сначала убрать CNAME и дождаться, пока истечёт его TTL, и только потом удалять проект или бакет на внешнем хостинге. Иначе даже если про DNS не забыли, остаётся окно, когда имя на площадке уже освободилось, а старые DNS-кэши всё ещё ведут туда. По-хорошему, удаление внешнего ресурса вообще стоит разрешать только после проверки, что наши записи на него больше не ссылаются.


    1. AVX
      04.09.2026 15:24

      Так и надо делать. Аналогично и с внутренними сервисами - если вводят новый вместо старого, после тестов переключают в днс запись на новый адрес (или если имя новое - запись удаляют), но старый сервис не выключают, а ставят на мониторинг, есть ли туда ещë запросы, и откуда они. Как только запросов больше нет какое-то время - можно и гасить.


  1. lazarus_net
    04.09.2026 15:24

    A не размещать корпоративные проекты не на корпоративном домене не пробовали? классический ССЗБ


  1. SanSYS
    04.09.2026 15:24

    и называется это subdomain takeover, и есть такого полно у любой мало мальски старой компании, но бедной ассет менежментом

    Чуть полезных ссылок https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/02-Configuration_and_Deployment_Management_Testing/10-Test_for_Subdomain_Takeover

    https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Subdomain_takeover


  1. Xelld
    04.09.2026 15:24

    Без перехода к декларативному управлению DNS и автоматизации толку от такого аудита с пометками будет мало, через год или два опять придется начинать заново.

    Кажется, сейчас почти у всех регистраторов есть API, под который либо есть провайдер для octodns/lexicon, либо его легко будет реализовать (BTW, на хабре есть моя статья про DNS IaC).

    А приземлять записи напрямую на конечные ресурсы в целом плохая практика, имхо, особенно - если сервисов много. Перенесите этот слой на прокси/балансировщики, так и ответственность размываться не будет, и управлять трафиком/конфигом/сертами/etc будет намного проще.