dns-cache-unbound-redis

Как работает DNSSEC

Проблема обычного DNS

Обычный DNS не проверяет подлинность ответов. Злоумышленник может перехватить ответ резолвера и подсунуть свой IP-адрес — клиент об этом не узнает.

DNSSEC (DNS Security Extensions) решает эту проблему: каждый набор записей подписывается криптографически. Резолвер проверяет подпись перед тем, как вернуть ответ клиенту.


Что такое DNS-зона

Зона — область ответственности. Каждый домен обслуживается конкретными NS-серверами, которые хранят файл зоны со всеми записями.

.                        ← корневая зона (13 корневых серверов)
├── org.                 ← зона .org
│   └── iana.org.        ← зона iana.org (серверы ICANN)
└── ru.
    └── yandex.ru.       ← зона yandex.ru (серверы Яндекса)

Что значит «подписать запись»

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

Процесс подписи:

1. Берём запись:
   iana.org.  3600  IN  A  192.0.32.8

2. Хэшируем (SHA-256) → получаем «отпечаток»:
   iana.org. A 192.0.32.8  →  a3f9c2...

3. Шифруем отпечаток приватным ключом ZSK:
   a3f9c2... + приватный ZSK  →  8b71de...  (это RRSIG)

RRSIG публикуется в DNS рядом с самой записью.

Процесс проверки на резолвере:

RRSIG приходит от авторитетного сервера в том же ответе, что и сама запись:

;; ANSWER SECTION:
iana.org.  3600  IN  A      192.0.32.8
iana.org.  3600  IN  RRSIG  A 8 2 3600 ... 8b71de...

RRSIG хранится прямо в файле зоны рядом с каждой подписанной записью. Владелец зоны подписал заранее, положил в зону — сервер раздаёт всем.

Получив ответ, резолвер проверяет подпись:

1. Хэшируем полученную A-запись:
   iana.org. A 192.0.32.8  →  SHA-256  →  a3f9c2...

2. Расшифровываем RRSIG публичным ключом ZSK:
   8b71de... + публичный ZSK  →  a3f9c2...

3. Сравниваем:
   a3f9c2... == a3f9c2...  ✓  →  запись подлинная

Подделать RRSIG без приватного ключа математически невозможно.


Почему есть два ключа: ZSK и KSK

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

Поэтому роли разделены:

  ZSK (Zone Signing Key) KSK (Key Signing Key)
Что подписывает Все записи зоны (A, MX, NS…) Только DNSKEY-запись (то есть сам ZSK)
Как часто меняется Часто (раз в месяц) Редко (раз в год и реже)
Где хранится хэш Нигде — его проверяет KSK В DS-записи родительской зоны

ZSK можно менять часто — регистратор не нужен. KSK меняется редко — DS-запись у регистратора обновляется раз в год.


Цепочка доверия

Якорь доверия — в Unbound жёстко зашит хэш ключа корневой зоны (.). Это отправная точка, которой резолвер доверяет безусловно.

Дальше цепочка строится через DS-записи (Delegation Signer — хэш KSK дочерней зоны, хранится в родительской зоне):

Якорь доверия (зашит в Unbound)
    ↓ доверяем
Ключ корня (.)  →  проверяет DS зоны .org
    ↓ доверяем
Ключ .org  →  проверяет DS зоны iana.org
    ↓ доверяем
KSK iana.org  →  проверяет ZSK iana.org (через RRSIG на DNSKEY)
    ↓ доверяем
ZSK iana.org  →  проверяет A, MX, NS... (через RRSIG на каждой записи)
    ↓ доверяем
192.0.32.8  ←  это число точно настоящее

Полный алгоритм запроса

Подготовка владельца зоны (один раз)

1. Создать два ключа: ZSK и KSK (приватный + публичный для каждого).
   Приватные ключи хранятся в секрете у владельца зоны — нигде не публикуются.

2. Публичный ZSK и публичный KSK опубликовать в зоне как DNSKEY-записи.

3. Подписать все записи зоны (A, MX, NS...) приватным ZSK
   → получаем RRSIG для каждой записи.

4. Подписать DNSKEY-записи (содержащие публичные ZSK и KSK) приватным KSK
   → получаем RRSIG для DNSKEY.
   Таким образом KSK «ручается» за публичный ZSK.

5. Вычислить хэш публичного KSK → передать регистратору как DS-запись.
   Регистратор публикует DS в родительской зоне (.org).

Проверка на резолвере (при каждом запросе iana.org A)

1. Резолвер идёт к корню → получает NS .org + DS iana.org + RRSIG(DS)
2. Проверяет RRSIG(DS) через ключ корня (из якоря) ✓
3. Идёт к серверам iana.org → получает DNSKEY (ZSK+KSK) + RRSIG(DNSKEY)
4. Хэширует KSK → сравнивает с DS из шага 1 ✓  →  KSK доверенный
5. Проверяет RRSIG(DNSKEY) через KSK ✓  →  ZSK доверенный
6. Запрашивает A-запись + RRSIG(A)
7. Проверяет RRSIG(A) через ZSK ✓  →  возвращает 192.0.32.8

Если хотя бы одна проверка провалилась — резолвер возвращает SERVFAIL.


Флаг ad в dig

;; flags: qr rd ra ad;

ad (Authenticated Data) — резолвер успешно проверил всю цепочку DNSSEC.


Почему domain-insecure нужен для local-zone

При создании local-zone: "iana.org" static локальные local-data не подписаны. Validator Unbound пытается проверить RRSIG → не находит → SERVFAIL.

Директива domain-insecure: "iana.org" говорит валидатору: не требуй подпись для этой зоны. Именно это позволяет подменить DNSSEC-зону локальными данными.