MAATRIX / Блог / Как DNSSEC доказывает, что ответ не подменили по дороге

Как DNSSEC доказывает, что ответ не подменили по дороге

MAATRIX

Когда браузер спрашивает «где живёт example.com», он получает IP-адрес и верит ему на слово. Обычный DNS не умеет отличить настоящий ответ авторитетного сервера от подделки, подсунутой кем-то по дороге. DNSSEC закрывает именно эту дыру — не шифрует запрос, а даёт резолверу способ математически проверить, что ответ действительно подписан владельцем домена и не изменился ни на бит. В статье — как устроена эта проверка от корневой зоны до конкретной записи и что происходит на каждом шаге.

Почему обычный DNS-ответ можно подделать

DNS исторически строился как протокол без аутентификации ответа. Резолвер отправляет UDP-запрos авторитетному серверу (или следующему резолверу выше по цепочке) и принимает первый пришедший ответ, у которого совпали транзакционный ID, порт и вопрос. Больше проверять нечего — сам протокол не предусматривает подписи.

Отсюда два класса атак:

  • Подмена в канале (on-path spoofing). Если атакующий сидит между клиентом и резолвером — в той же Wi-Fi сети, на скомпрометированном маршрутизаторе, на транзитном узле — он может ответить на UDP-запрос раньше настоящего сервера, подсунув свой IP вместо правильного.
  • Отравление кэша (cache poisoning). Атакующий не обязан находиться в канале постоянно: если он угадает транзакционный ID и порт исходящего запроса резолвера (или проэксплуатирует резолвер, у которого эти параметры предсказуемы), он может «впрыснуть» поддельную запись в кэш резолвера. Дальше уже не нужно быть в канале — резолвер сам годами будет отдавать подмену всем, кто у него спрашивает, пока не истечёт TTL или кэш не почистят.

В обоих случаях итог одинаковый: пользователь стучится на IP, который выбрал не владелец домена, а третья сторона. Дальше это может быть перехват почты (через поддельную MX-запись), выдача чужого TLS-сертификата через центр сертификации, который полагается на DNS-подтверждение домена, или просто фишинговая копия сайта.

Важно понимать границы: DNSSEC не шифрует трафик и не прячет, какой домен вы спрашиваете — этим занимаются DNS over TLS и DNS over HTTPS, которые защищают транспорт между вами и резолвером. DNSSEC решает другую задачу — доказывает подлинность содержимого ответа независимо от того, кто и как его передал, вплоть до резолвера, которому вы верите.

DNSSEC: что за цепочка доверия и откуда она начинается

Идея DNSSEC простая: каждая зона подписывает свои записи закрытым ключом, а резолвер проверяет подпись открытым ключом. Проблема в том, что открытый ключ тоже нужно откуда-то знать — иначе атакующий подменит и его вместе с ответом. Решение — выстроить ключи в цепочку, где каждое звено подтверждает следующее, а самое первое звено резолвер знает заранее и без вопросов.

Это первое звено — корневая зона DNS (.). У неё есть собственный ключ (root KSK), отпечаток которого «зашит» в резолвер как доверенный якорь (trust anchor) — точно так же, как в браузер зашиты корневые сертификаты для проверки TLS. Резолверу не нужно спрашивать «а этому ключу можно верить» — он верит ему по определению, потому что администратор резолвера (или его дистрибутив) явно об этом заявил.

Дальше цепочка строится вниз, зона за зоной:

корень (.)
  └─ подтверждает ключ зоны .io
       └─ .io подтверждает ключ зоны example.io
            └─ example.io подписывает саму запись A/MX/TXT

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

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Из чего состоит цепочка — DNSKEY, RRSIG, DS

Технически цепочка держится на трёх типах записей, которые публикует сама зона.

DNSKEY — открытые ключи зоны. Их обычно два вида, с разными ролями:

  • ZSK (Zone Signing Key) — рутинный ключ, которым подписывается каждая обычная запись зоны (A, MX, TXT и так далее). Меняется чаще, потому что подписывает много данных и его удобнее ротировать без лишней бюрократии.
  • KSK (Key Signing Key) — ключ, которым подписывается сам набор DNSKEY-записей зоны (то есть он подтверждает ZSK). Меняется реже, потому что его отпечаток должен быть согласован с родительской зоной — а это уже не внутреннее дело владельца домена.

RRSIG — собственно подпись. Для каждого набора записей одного типа (RRset) публикуется отдельная RRSIG, покрывающая все записи этого типа целиком: например, все A-записи example.io подписываются одной подписью, а не каждая по отдельности. В RRSIG зашиты алгоритм подписи, срок действия (не то же самое, что TTL — подпись может «протухнуть» задолго до истечения кэша) и указание, каким ключом подписано.

DS (Delegation Signer) — запись, которая живёт не в самой зоне, а в родительской. Это хэш от KSK дочерней зоны. Именно DS-запись превращает набор ключей example.io из «просто чьих-то ключей» в «ключей, которые подтверждены владельцем зоны .io». Без DS-записи в родителе цепочка обрывается — резолвер видит подписанную зону, но не может связать её ключ с уже проверенным звеном выше.

Практический вывод: включить DNSSEC на домене — это не одна операция, а две, в разных местах. Сначала DNS-провайдер подписывает зону и генерирует KSK/ZSK. Потом хэш KSK нужно опубликовать как DS-запись у регистратора домена, который передаст её в родительскую зону (TLD). Если сделать только первый шаг и забыть про второй, зона технически подписана, но цепочка доверия никуда не ведёт — с точки зрения валидирующего резолвера это просто зона без DNSSEC, только более медленная в ответах из-за лишних RRSIG-записей.

Как резолвер проверяет ответ шаг за шагом

Возьмём конкретный запрос: клиент спрашивает A-запись www.example.io. Валидирующий резолвер (тот, что умеет проверять DNSSEC — это не все резолверы) делает примерно следующее:

  1. Получает ответ: A-запись плюс RRSIG для неё.
  2. Запрашивает DNSKEY-набор зоны example.io, чтобы найти ZSK, которым подписана эта RRSIG.
  3. Проверяет подпись RRSIG открытым ZSK — математически убеждается, что A-запись не менялась после подписи.
  4. Но сам DNSKEY-набор (включая ZSK) тоже подписан — RRSIG над DNSKEY, сделанной с помощью KSK. Резолвер проверяет и эту подпись.
  5. Остаётся вопрос: а этому KSK можно верить? Резолвер идёт в родительскую зону .io и запрашивает DS-запись для example.io. Если хэш из DS совпадает с хэшем KSK, который резолвер только что проверил — связь подтверждена.
  6. Но DS-запись в зоне .io тоже подписана своим RRSIG, который проверяется ключом DNSKEY зоны .io — и вся процедура повторяется на уровень выше: DS для .io ищется уже в корневой зоне.
  7. На корне цепочка замыкается: ключ корневой зоны резолвер не проверяет через DS «выше», потому что выше уже ничего нет — он сверяет его напрямую с зашитым доверенным якорем.

Если каждая проверка на этом пути прошла успешно, резолвер помечает ответ как аутентифицированный — в заголовке DNS-ответа выставляется флаг AD (Authenticated Data). Если хоть одна подпись не сошлась, истёк срок действия RRSIG, или в цепочке не хватило DS-записи там, где она ожидалась — резолвер, настроенный на строгую проверку, вернёт SERVFAIL вместо ответа, а не молча отдаст непроверенные данные.

Важный нюанс: всю эту цепочку проверяет резолвер, а не приложение на конечном устройстве. Обычный dig или системный резолвер стаба на ноутбуке доверяет флагу AD, который выставил вышестоящий резолвер — то есть на последнем отрезке (от локального резолвера до вашего приложения) защита держится не на DNSSEC, а на том, что этот канал вы считаете доверенным (обычно localhost или защищённая локальная сеть). Если нужна проверка end-to-end на самом устройстве, приложение должно валидировать DNSSEC самостоятельно или резолвер и клиент должны быть связаны по DNS over TLS/HTTPS — это отдельный вопрос транспорта, а не аутентификации данных.

Проверить цепочку вручную можно dig-ом с флагом +dnssec или более подробной утилитой delv, которая как раз показывает весь путь валидации:

dig +dnssec A www.example.io

delv www.example.io

delv печатает по каждому звену, была ли проверка успешной, а если что-то не сошлось — на каком именно шаге цепочка оборвалась.

Как доказать, что записи не существует — NSEC и NSEC3

Отдельная и не всегда очевидная задача — доказать отсутствие записи. Если кто-то спрашивает nosuchhost.example.io, а такой записи нет, обычный DNS просто отвечает NXDOMAIN без подписи — и этот ответ так же уязвим к подмене, как и положительный. Атакующий может заставить резолвер поверить, что существующий домен не существует (например, чтобы сорвать проверку домена при выпуске TLS-сертификата) или наоборот.

DNSSEC решает это через аутентифицированное отрицание существования — записи NSEC или NSEC3.

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

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

NSEC3 решает эту проблему, публикуя не сами имена, а их хэши в том же упорядоченном виде. Доказательство отсутствия работает так же, но перечислить исходные имена по хэшам напрямую нельзя (хотя короткие или предсказуемые имена всё равно можно восстановить перебором — NSEC3 усложняет разведку, а не исключает её полностью). Именно поэтому NSEC3 сейчас используется чаще NSEC как настройка по умолчанию у большинства DNS-провайдеров.

Как включить и проверить DNSSEC на своём домене

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

Если зона обслуживается PowerDNS, включение DNSSEC для уже существующей зоны выглядит так:

pdnsutil secure-zone example.io
pdnsutil rectify-zone example.io
pdnsutil show-zone example.io

Последняя команда покажет текущие ключи (KSK и ZSK) и, что важнее, готовую DS-запись, которую нужно скопировать к регистратору.

Если зона на BIND, DNSSEC чаще всего включают через inline-signing: генерируют ключи dnssec-keygen, кладут их рядом с зоной и добавляют в конфиг зоны директиву inline-signing yes; auto-dnssec maintain; — сервер сам подписывает записи и следит за сроками действия подписей.

Дальше — общий для любого DNS-сервера шаг: DS-запись из вывода утилиты (или отдельного файла dsset-example.io.) нужно вставить в панели управления регистратора домена, в разделе DNSSEC (обычно рядом с настройкой NS-серверов). Без этого шага зона подписана, но цепочка обрывается на границе делегирования — регистратор не подтверждает ключ, и он остаётся «сиротой».

После публикации DS-записи стоит подождать, пока изменение разойдётся (обычно это связано со сроком кэширования родительской зоны, а не с DNSSEC напрямую), и проверить результат:

dig +dnssec DS example.io @<родительский-DNS>
delv example.io

Если delv показывает успешную валидацию по всей цепочке — DNSSEC работает.

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

Если DNS-сервер вы администрируете сами — например, на арендованном VPS — есть смысл посмотреть на пошаговую установку PowerDNS, где включение DNSSEC логично встраивается в общую настройку зоны. А как выглядит сама цепочка резолверов, через которую проходит запрос прежде чем добраться до авторитетного сервера, подробно разобрано в статье про путь DNS-запроса через сеть.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

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

DNSSEC защищает от DDoS на DNS-сервер?

Нет, это про другое: DNSSEC доказывает подлинность ответа, а не защищает доступность сервера. От DDoS помогают анти-DDoS перед DNS-сервером, ограничение скорости запросов и распределённые авторитетные серверы — DNSSEC тут ни при чём и даже слегка увеличивает нагрузку, потому что подписанные ответы больше по размеру.

Если у меня нет DNSSEC, меня легко взломают через DNS?

Не обязательно легко, но риск реален там, где резолвер уязвим или атакующий может оказаться в канале — например, в публичных сетях Wi-Fi или на скомпрометированной инфраструктуре провайдера. DNSSEC закрывает именно этот класс атак; остальные угрозы (фишинг, уязвимости в приложении) он не решает.

DNSSEC связан с NSEC и с TLS-сертификатами напрямую?

Формально нет — NSEC/NSEC3 работают только внутри DNSSEC для доказательства отсутствия записи. Но на практике многие центры сертификации при выпуске TLS-сертификата проверяют владение доменом через DNS (TXT-запись), и если DNS можно подделать, можно попытаться выпустить сертификат на чужой домен — тут DNSSEC служит дополнительным барьером, хотя сам процесс выпуска сертификата от него не зависит напрямую.

Почему домен может быть недоступен именно после включения DNSSEC?

Чаще всего это рассинхронизация DS-записи у регистратора с реальным ключом на DNS-сервере — например, после смены KSK забыли обновить DS. Резолверы со строгой валидацией в этом случае отвечают SERVFAIL вместо реального адреса. Первым делом при такой проблеме стоит сверить DS-запись у регистратора с текущим KSK на сервере через pdnsutil show-zone или аналогичную команду.

Нужно ли включать DNSSEC на каждом поддомене отдельно?

Нет, если родительская зона подписана и делегирование настроено правильно — подпись распространяется на всю иерархию имён внутри зоны. Отдельная настройка нужна только если поддомен вынесен в собственную делегированную зону с отдельным NS-набором — тогда для него нужна своя цепочка DNSKEY/DS, как для отдельного домена.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →