Современное объединение вычислительных IP-сетей, ранее известное как “Интернет”, обладает интересными особенностями, которые прямо связаны с практической трактовкой термина “сетевая прозрачность” разработчиками приложений.

Например, ранее такой разработчик мог успешно использовать абстракцию TCP-сокета: если установлено соединение с некоторым удалённым узлом через такой абстрактный сокет, то просто пишем в сокет байты данных, предназначенные удалённому узлу, а читаем – данные, которые тот узел прислал. На этом “дуплексном” потоке можно строить прикладной протокол, реализующий уже сервис для конкретной задачи – например, отправку потокового видео, или какой-нибудь телеметрии. Сам этот верхнеуровневый протокол тут не важен. Важно, что подлежащий TCP-сокет рассматривается как транспорт с “сетевой прозрачностью” – то есть, этот сокет одинаково прозрачен для разных верхнеуровневых протоколов. Однако сейчас это уже далеко не всегда так: глобальная Сеть, если наблюдать с точки зрения описанных сокетов, оказывается непрозрачной именно для разных протоколов, которые уровнем выше сокета. Одна телеметрия проходит, а другая – уже нет. Какой-то протокол работает только в одну сторону. Но транспортный сокет (пусть, TCP) открыт один и тот же.

Получается, что разработчик приложения, если ему важно сохранение связности на максимально высоком, прикладном уровне, больше не может считать сетевой сокет “абстрактным”, как не может этот разработчик и дальше абстрагироваться от состава, предположим, IP-пакетов, порождаемых при обработке потоков высокоуровневого протокола. Разработчику, получается, приходится преследовать цель обретения прозрачности, модифицируя свой прикладной, верхнеуровневый протокол таким образом, чтобы менялся состав данных внутри сокета и поведение системной библиотеки, обеспечивающей работу сокета. То есть, разработчик, буквально, прицеливается на достаточно низкоровневые особенности: перебор адресов, замена номеров портов, отказ от сигнатур в заголовках и так далее.

Теперь не просто уровни перемешиваются (я как-то про это писал отдельно), но особенности, проявляющиеся в результате анализа поведения сети за сокетом, на низком уровне, просачиваются на уровень верхний, который ранее считался “абстрактным”.

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



Comments Off on Приложения и разбитые абстракции интернетов

(Это дополненная и скорректированная версия статьи, которую я некоторое время назад публиковал на “Хабре”.)

Данные в запросах и ответах классической DNS никак не защищены, передаются в открытом виде. DNS-over-TLS (DoT, RFC 7858) предоставляет один из инструментов защиты информации, а именно: защиту DNS-запросов и DNS-ответов от прослушивания на промежуточных узлах.

DoT использует TLS для зашифрования DNS-транзакций, передаваемых между узлами, но не защищает сами DNS-данные. Под “DNS-данными” тут подразумевается состав ответов и запросов DNS: имена и записи. То есть, если ваш локальный компьютер использует DoT для работы с DNS-сервером, то передаваемые DNS-данные не видны “на транзите” (как объясняется ниже, сам факт обмена DNS-данными обычно всё равно виден) и нельзя простым способом узнать, для какого узла и какие DNS-запросы направлялись. Однако, если DNS-сервер, к которому запросы отправлялись с защитой DoT, возвращает неверные, искажённые DNS-данные, – например, подставляет собственный IP-адрес для, условно, example.com, – то DoT ничего с этим поделать не может – тут уже нужно использовать DNSSEC.

На всякий случай, замечу: DoT – это технология, которая никак не связана с DNS-over-HTTPS (DoH). Архитектура DoT довольно логичная: TLS здесь используется в качестве инструмента создания защищённого “сокета” между DNS-клиентом и DNS-сервером. Через “сокет” передаются те же DNS-запросы/DNS-ответы, как они передавались бы на уровне обычного UDP или TCP. То есть “сокет” с TLS тут нужно считать туннелем, работа которого прозрачна для уровня DNS. Естественно, чтобы использовать DoT в таком прозрачном режиме, нужна поддержка TLS и на клиенте, и на сервере. Однако, поскольку спецификация отводит TLS обособленный уровень (в отличие от DoH), ничто не мешает поднять TLS-соединение между узлами какими-то другим способом, установив тем самым туннель, а запросы/ответы от неподдерживающих TLS клиентов/серверов перенаправлять без изменений через этот туннель.

Вспомним самые базовые свойства DNS как сервиса поиска данных. Эти свойства важны для понимания места DoT в уже построенной инфраструктуре. DNS – сложная система, работающая по сложным и, что называется, “развесистым” протоколам (простой эта система только кажется; в чём, надеюсь, можно убедиться даже по результатам чтения данной небольшой статьи). Внедрение TLS в DNS заметно усложняет архитектуру, но конкретно DoT позволяет внести изменения почти оптимальным образом.

Типовой сценарий работы DNS это так называемый рекурсивный опрос, в котором специальный DNS-сервер (резолвер) производит обход других DNS-серверов (которые называются “авторитативными”), следуя по веткам дерева делегирования с целью поиска данных, соответствующих некоторому ключу. Хрестоматийный пример: в качестве ключа выступает имя хоста (example.com), а целевыми данными является IP-адрес (значение адресной A-записи), то есть, “хотим найти IP-адрес для имени сервера”. DNS правильно рассматривать именно как специальную распределённую базу данных и сервис поиска в этой базе данных. Собственно, сама аббревиатура DNS может расшифровываться двумя способами: Domain Name System и Domain Name Service. DoT – относится к транспорту для сервиса поиска и позволяет защитить трафик каждого DNS-запроса на каждом отрезке. (А криптографическая система на уровне базы данных DNS – это как раз DNSSEC, но DNSSEC не зашифровывает данные.)

Рекурсивный DNS-резолвер, если подходящий ответ отсутствует в кеше, обращается к разным авторитативным серверам Интернета по некоторому довольно сложному алгоритму и, при штатной работе системы, либо получает от сервера нужный ответ о целевом имени, либо получает так называемый делегирующий ответ, который содержит имена других авторитативных серверов и позволяет резолверу продолжить поиск, обращаясь уже к каким-то из этих серверов (откуда и появляется “рекурсия” в названии процесса). При этом рекурсивный резолвер обычно находится за пределами “локальной машины”. В качестве рекурсивного резолвера может выступать сервер провайдера интернет-доступа или публичный сервис типа Google Public DNS 8.8.8.8. На локальной машине DNS-запросы обрабатывает более простая программа – stub-резолвер, который только перенаправляет запросы рекурсивному резолверу (иногда его ещё называют “рекурсор”) и принимает от него ответы. DoT может использоваться на любом участке работы DNS: не только на “последней миле”, то есть на отрезке от локального stub-резолвера к рекурсивному резолверу, но и между авторитативными серверами. Кстати, эта “последняя миля” в современных браузерах как раз часто защищена при помощи DNS-over-HTTPS.

Итак, общая логика работы DoT следующая:

1) произвольный DNS-клиент, если он поддерживает TLS, устанавливает TLS-соединение, подключившись по TCP к DNS-серверу (для UDP есть отдельный вариант – DNS-over-DTLS, здесь можно считать, что он работает так же, как и DoT);
2) DNS-клиент может провести аутентификацию сервера различными способами (см. ниже);
3) если TLS-соединение установлено, то DNS-клиент переходит к отправке DNS-запроса обычным способом, но уже через TLS-соединение;
4) ответ DNS-сервера доставляется в рамках того же TLS-соединения; при этом формат DNS-ответа и прочие свойства – не изменяются, если сравнивать с работой DNS непосредственно по UDP или TCP, без TLS-туннеля (см. ниже);
5) TLS-соединение закрывается, если клиент не планирует использовать его далее.

Для DoT выделен номер порта 853 (классический номер порта DNS – 53). Поэтому клиенты могут сразу пробовать использовать DoT, подключаясь по TCP на номере порта 853. Так как DoT – универсальная спецификация, то такое подключение можно устанавливать и к авторитативным серверам. Но сейчас поддержка DoT на авторитативных серверах является большой редкостью. Тем не менее, DoT поддерживают, например, серверы DNS-зон facebook.com и wikimedia.org.

Практика

Воспользуемся утилитой dig из пакета BIND и посмотрим, как DoT работает вживую на авторитативных серверах. В качестве источника примеров используем зону wikimedia.org, авторитативные серверы имён которой поддерживают DoT.

Утилита dig – это один из типовых инструментов из области DNS. В более или менее современной версии dig умеет в DoT сразу из коробки: нужно просто указывать опцию +tls при вызове. Я здесь использую версию 9.18.33-1 под Raspberry Pi OS (Debian 12).

Сначала определим, на какие серверы делегирована зона wikimedia.org (пока что без DoT), это делается запросом NS-записей (-t NS):

$ dig -t NS +short wikimedia.org
ns1.wikimedia.org.
ns2.wikimedia.org.
ns0.wikimedia.org.

(+short здесь – это краткий формат вывода.)

Наша цель – отправить запрос AAAA-записи (IPv6-адрес) через DoT и получить ответ, посмотрев, с помощью tshark, что происходит в трафике. Кроме того, мы извлечём серверный TLS-сертификат с авторитативного сервера и глянем, что там, в сертификате, написано. Будем использовать авторитативный сервер ns1.wikimedia.org. Однако сначала определим его IPv4-адрес, чтобы DNS-запросы отправлять непосредственно серверу.

$ dig -t A +short ns1.wikimedia.org.
208.80.153.231

Запросили A-запись – получили IPv4-адрес в ответ. Теперь включаем DoT (и тут вообще будет опций побольше, но все они объяснены ниже):

$  dig -t AAAA @208.80.153.231 +tls +nocookie +norec wikimedia.org

; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> -t AAAA @208.80.153.231 +tls +nocookie +norec wikimedia.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44438
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; TCP KEEPALIVE: 157.0 secs
; PAD: (388 bytes)
;; QUESTION SECTION:
;wikimedia.org.			IN	AAAA

;; ANSWER SECTION:
wikimedia.org.		300	IN	AAAA	2a02:ec80:300:ed1a::1

;; Query time: 300 msec
;; SERVER: 208.80.153.231#853(208.80.153.231) (TLS)
;; WHEN: Sun Mar 16 18:18:01 MSK 2025
;; MSG SIZE  rcvd: 468

(Опции: +tls - используем DoT, +nocookie - без куки-меток, чтобы не перегружать вывод (DNS-куки не относятся к DoT и тут не рассматриваются: про них планирую отдельную записку опубликовать), +norec - не устанавливаем флаг рекурсии.)

Здесь уже в нижнем информационном блоке видно, что запрос и ответ передавались с использованием TLS, через TCP-соединение на номере порта 853. То есть, это DoT.
Дополнительно подтвердить, что трафик ходил через TLS, можно при помощи tshark, посмотрев в дамп, записанный tcpdump (это два основных инструмента).

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

# tcpdump -i eth0 -w pcap-dns.pcap

Парсинг дампа при помощи tshark:

$ tshark -r pcap-dns.pcap -o tls.keylog_file:keylog.log -O tls,dns -S "-----PACKET-----" -x

Здесь: -r - входной PCAP-файл; -o tls.keylog_file:keylog.log - это импорт сессионных ключей TLS, они потребуются для раскрытия DNS-трафика (про способ экспорта кратко рассказано ниже); -O tls,dns - перечень протоколов для парсера; -S "..." - разделитель "пакетов" в распечатке дампа, можно использовать любую удобную строку; -x - выводить hex-дамп тоже.

В распечатке дампа находим примерно следующее:

Internet Protocol Version 4, Src: 192.168.1.13, Dst: 208.80.153.231
Transmission Control Protocol, Src Port: 36461, Dst Port: 853, Seq: 1, Ack: 1, Len: 303
Transport Layer Security
    TLSv1 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 298
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 294
            Version: TLS 1.2 (0x0303)

Это часть сообщения ClientHello, направленного утилитой dig авторитативному DNS-серверу. Соответствующее серверное сообщение ServerHello, которое можно найти в дампе, вместе с возможностью расшифровывать трафик, означает, что узлы успешно установили соединение TLS 1.3. Внутри TLS-соединения передан DNS-запрос и получен DNS-ответ.

Чтобы посмотреть прикладной трафик внутри TLS, нужно экспортировать сессионные ключи - то есть, симметричные секреты, которые стороны использовали для зашифрования трафика. Конкретный способ экспорта зависит от параметров сборки dig и системного окружения, но обычно достаточно установить переменную окружения SSLKEYLOGFILE, чтобы dig, при использовании TLS, выводила ключи в файл или в STDERR (откуда их можно точно так же скопировать). Механика экспорта TLS-ключей не относится к теме данной статьи, поэтому детали остаются за скобками. А вот выдачу tshark для расшифрованного DNS-трафика - посмотрим. Запрос:

Transport Layer Security
    TLSv1.3 Record Layer: Application Data Protocol: Domain Name System
        Opaque Type: Application Data (23)
        Version: TLS 1.2 (0x0303)
        Length: 61
        [Content Type: Application Data (23)]
        Encrypted Application Data: [...]
        [Application Data Protocol: Domain Name System]
Domain Name System (query)
    Length: 42
    Transaction ID: 0xad96
    Flags: 0x0020 Standard query
        0... .... .... .... = Response: Message is a query
        .000 0... .... .... = Opcode: Standard query (0)
        .... ..0. .... .... = Truncated: Message is not truncated
        .... ...0 .... .... = Recursion desired: Don't do query recursively
        .... .... .0.. .... = Z: reserved (0)
        .... .... ..1. .... = AD bit: Set
        .... .... ...0 .... = Non-authenticated data: Unacceptable
    Questions: 1
    Answer RRs: 0
    Authority RRs: 0
    Additional RRs: 1
    Queries
        wikimedia.org: type AAAA, class IN
            Name: wikimedia.org
            [Name Length: 13]
            [Label Count: 2]
            Type: AAAA (IPv6 Address) (28)
            Class: IN (0x0001)
[...]

Здесь и далее часть данных (опции EDNS и пр.) удалена, чтобы не слишком растягивать распечатку. В блоке Flags можно видеть параметры запроса, как его сформировала утилита dig. А в блоке Queries (сам запрос) - имя wikimedia.org. и состав запроса IN AAAA. Обратите внимание на поле [Application Data Protocol: Domain Name System]. Вообще, то, что TLS-сессия используется для DoT, видно не только по номеру порта, но и по идентификатору протокола уровня приложений, который dig передаёт в составе начального TLS-сообщения ClientHello. Выглядит это вот так:

Extension: application_layer_protocol_negotiation (len=6)
  Type: application_layer_protocol_negotiation (16)
   Length: 6
    ALPN Extension Length: 4
    ALPN Protocol
     ALPN string length: 3
     ALPN Next Protocol: dot

ALPN - это Application Layer Protocol Negotiation, расширение ClientHello, которое позволяет сразу сообщить серверу, какой именно прикладной протокол будет использован поверх этого соединения. Для DoT зарезервирован идентификатор 0x646F74 (то есть, строка "dot" в ASCII). Расширение передаётся в открытом виде, поэтому системе, инспектирующей трафик, нетрудно классифицировать TLS-сессию как сессию DNS: номер порта и идентификатор протокола - этого вполне достаточно. Понятно, что ни TLS, ни DoT и не ставят своей целью сокрытие факта соединения.

Просматривая выдачу tshark далее, находим DNS-ответ:

Transport Layer Security
    TLSv1.3 Record Layer: Application Data Protocol: Domain Name System
        Opaque Type: Application Data (23)
        Version: TLS 1.2 (0x0303)
        Length: 487
        [Content Type: Application Data (23)]
        Encrypted Application Data: [...]
        [Application Data Protocol: Domain Name System]
Domain Name System (response)
    Length: 468
    Transaction ID: 0xad96
    Flags: 0x8400 Standard query response, No error
        1... .... .... .... = Response: Message is a response
        .000 0... .... .... = Opcode: Standard query (0)
        .... .1.. .... .... = Authoritative: Server is an authority for domain
        .... ..0. .... .... = Truncated: Message is not truncated
        .... ...0 .... .... = Recursion desired: Don't do query recursively
        .... .... 0... .... = Recursion available: Server can't do recursive queries
        .... .... .0.. .... = Z: reserved (0)
        .... .... ..0. .... = Answer authenticated: Answer/authority portion was not authenticated by the server
        .... .... ...0 .... = Non-authenticated data: Unacceptable
        .... .... .... 0000 = Reply code: No error (0)
    Questions: 1
    Answer RRs: 1
    Authority RRs: 0
    Additional RRs: 1
    Queries
        wikimedia.org: type AAAA, class IN
            Name: wikimedia.org
            [Name Length: 13]
            [Label Count: 2]
            Type: AAAA (IPv6 Address) (28)
            Class: IN (0x0001)
    Answers
        wikimedia.org: type AAAA, class IN, addr 2a02:ec80:300:ed1a::1
            Name: wikimedia.org
            Type: AAAA (IPv6 Address) (28)
            Class: IN (0x0001)
            Time to live: 300 (5 minutes)
            Data length: 16
            AAAA Address: 2a02:ec80:300:ed1a::1
    Additional records
        : type OPT
            Name: 
            Type: OPT (41)
[...]
            Option: EDNS TCP Keepalive
                Option Code: EDNS TCP Keepalive (11)
                Option Length: 2
                Option Data: 0622
                Timeout: 1570
            Option: PADDING
                Option Code: PADDING (12)
                Option Length: 388
                Option Data: 00…
                Padding: 00…

Это исходник DNS-ответа, который был отображён dig (см. распечатку выше). Обратите внимание на секцию "опций", вот её копия из выдачи dig:

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; TCP KEEPALIVE: 157.0 secs
; PAD: (388 bytes)

Здесь мы, например, без труда видим, что параметр TCP Keepalive имеет значение 157 секунд, как и в распечатке tshark, а дополнение (padding) совпадает по длине (388 октетов). Как нетрудно догадаться по названию, TCP Keepalive содержит указание на интервал времени, в течение которого сервер (в данном случае) готов поддерживать контекст TCP-соединения, чтобы клиент мог реализовать конвейеризацию запросов. К DoT это относится весьма косвенно, но зато служит прекрасным примером реальной сложности современных DNS-протоколов (про Keepalive в DNS тоже можно написать отдельную статью, как ни странно).

А вот дополнение (padding) к DoT относится в большей степени, чем Keepalive, хоть и так же находится за пределами конкретно DoT. Идея использования дополнения здесь в том, чтобы можно было изменять длину блоков данных, содержащих DNS-транзакции, не влияя на сами транзакции. Если длину блоков выравнивать, то это позволяет сделать семантически разные блоки неразличимыми по длине. Что, кстати, особенно важно, если блоки зашифрованы. Проще говоря, наблюдая трафик, состоящий из разных по длине блоков данных, где длина определяется форматом, можно выстроить корреляцию с конкретными DNS-запросами и ответами по порядку их следования. Ведь параметры известны: длина доменного имени, длина "флагов" и заголовков, количество DNS-записей в ответах и т.д. Это позволит сделать предположения о составе наблюдаемого трафика, даже без раскрытия самого его содержания. Если же вы наблюдаете только ровный конвейер блоков одинаковой длины, в стиле "запрос-ответ, всё в одинаковых коробках", то извлечь дополнительную информацию гораздо сложнее. Естественно, можно при помощи дополнения варьировать длину и так, чтобы, напротив, блоки не были одинаковыми по количеству байтов. Заметьте, что аналогичный механизм выравнивания длины записей с помощью дополнения есть и в TLS 1.3.

TLS-сессия использует серверный сертификат. Для авторитативного сервера ns1.wikimedia.org. TLS-сертификат можно получить из дампа трафика (но, так как там TLS 1.3, придётся расшифровать отдельно), а можно воспользоваться утилитой s_client из OpenSSL: TLS в DoT точно такой же, как и в других случаях, так что s_client сработает прекрасно, нужно лишь подключиться по номеру порта 853, вот так:

$ openssl s_client -connect 208.80.153.231:853

Cертификаты в TLS нужны для аутентификации узлов, то есть для установления подлинности этих узлов. Однако в DoT с сертификатами связаны свои особенности.

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

Технически, ничто не мешает выпустить сертфикат для IP-адреса. Если говорить про имеющиеся "хорошо известные УЦ", то сертификаты для IP-адресов пока что выпускают неохотно, так как есть трудности с надёжной проверкой права управления адресом, а также с сопровождением. Впрочем, Let's Encrypt обещают довольно скоро сделать автоматические короткоживущие TLS-сертификаты на IP-адреса для всех, используя механизм подтверждения управления адресом чисто по TLS. Это должно позволить в прозрачном режиме привязать ACME-проверку к DoT, не поднимая ненужного, в данном случае, веб-сервера.

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

В-третьих, DoT использует "приспособительный" подход и к аутентификации, и к TLS в целом. Это то, что в англоязычной традиции называется Opportunistic Security - "если удалось, то обязательно будем аутентифицировать и зашифровывать, а если нет - тогда ладно".

Может показаться, что если серверный сертификат не проверять, то от TLS для DNS нет никакого толку: промежуточный узел может перехватить соединение и подставить свой, произвольный сертификат, подходящий по формату. Однако в случае DoT схема, как минимум, всегда защищает от пассивного прослушивания трафика. Пассивное прослушивание реализовать гораздо проще, чем активный перехват, а защита от утечек через "пассивные" каналы и является основной для DoT. Тем более, если речь идёт о работе с авторитативными DNS-серверами. Защита же от активной атаки может быть реализована на "последней миле", где клиенту, обычно, заранее известны некоторые данные о сервере: имя, ключ и так далее.

Кстати, посмотрим на имена и на интервал валидности сертификата, который вернул сервер ns1.wikimedia.org.:

        Serial Number:
            05:f7:71:aa:08:8e:32:88:0a:71:9c:2d:f3:98:17:e1:d6:aa
        Signature Algorithm: ecdsa-with-SHA384
        Issuer: C = US, O = Let's Encrypt, CN = E5
        Validity
            Not Before: Mar 16 05:02:56 2025 GMT
            Not After : Jun 14 05:02:55 2025 GMT
        Subject: CN = ns0.wikimedia.org

[...]
            X509v3 Subject Alternative Name: 
                DNS:ns0.wikimedia.org, DNS:ns1.wikimedia.org, DNS:ns2.wikimedia.org

Это сертификат, выпущенный Let's Encrypt. Subject пропускаем, смотрим в Subject Alternative Name, где указаны все три имени для трёх авторитативных серверов зоны wikimedia.org., которые мы нашли в самом начале этого экскурса в DoT силами dig.

DoT уже поддерживается основными программными пакетами авторитативных серверов и рекурсивных резолверов. Например, BIND и Unbound. Так что протокол можно внедрять не только на "последней миле", но и на авторитативных серверах, защищая трафик резолверов к этим серверам (и обратно).

Подведём итог. DoT, используя TLS, защищает данные от пассивного прослушивания третьей стороной. Если клиент применяет тот или иной метод аутентификации сервера, то DoT может защитить от активного перехвата и подмены данных. Но всё это работает только на том отрезке, где применяется DoT, а защита TLS не распространяется на сам состав DNS-данных. Чтобы защитить содержательную часть DNS, необходимо использовать DNSSEC, а эту технологию тоже можно изучать при помощи dig на практических DNS-зонах.



Комментировать »

Электронная почта, email – одна из немногих интернет-технологий уровня приложений, которая всё ещё сохраняет черты “старого интернета”, где общедоступные протоколы позволяли строить распределённые системы обмена сообщениями. Да, нельзя не заметить, что централизация нынче настигла и email, но заметка о другом – хотелось бы рассмотреть пару конкретных способов защиты от нежелательных сообщений, которые используются на почтовых серверах, но при этом настолько избыточны, что мешают доставлять вполне себе легитимные письма.

Способ первый – это требование наличия адресных записей в апексе почтовой зоны. Речь вот о чём: представьте, что доставляющий релей принёс письмо из домена example.com, а принимающий почтовый сервер требует, чтобы для этого example.com была указана A-запись (либо AAAA – не важно). То есть, принимающий сервер смотрит в DNS, обнаруживает, что в example.com нет A-записи и отбрасывает письмо. (Просто закрыть SMTP-сессию в самом начале этот сценарий не позволяет: нужно дождаться, когда клиент скажет, из какого домена, – якобы! – он принёс письмо.) Очевидно, данный способ предполагает, что “настоящие” доменные зоны не могут работать без адресных записей, а если такой записи нет, то и письмо – “подспуфлено”. Но это далеко не всегда так. Почтовый домен – это почтовый домен. Необязательно держать под тем же именем веб-сайт, предположим. Конечно, способ обоснован: пусть спецификация такого и не предписывает, но ведь можно потребовать, чтобы в почтовом домен был опубликован какой-то способ доставки почты, однако просто требовать наличия адресных записей – это слишком строго. Да, при отсутствии MX-записей почта может доставляться по A-записям. Это верно, но это не означает, что наличие Α-записи обязательно, если есть MX-записи. А вот легитимные письма, приходящие из чисто почтового и корректно настроенного домена, оказываются отброшены. Это плохо.

Данная проверка при фильтрации разумна только в том случае, если для почтового домена-отправителя не удалось найти MX-ы. Но обратите внимание, что, вообще говоря, наличие MX-записей, технически, не является обязательным при отправке сообщений: логика фильтрации тут строится на том, что если для почтового домена, из которого, якобы, пришло письмо, не опубликовано методов доставки сообщений, то и письмо-то какое-то липовое. Но наличие DNS-записей не гарантирует, что письма будут приняты. Есть и специальные адреса в стиле no-reply, и прочий /dev/null. Как говорится, ладно, допустим – однако отсутствие-то A-записи при наличии MX уж точно не может служить основанием для отбрасывания письма.

Вообще, изобретательная защита от нежелательных сообщений – мера вполне оправданная. Главное, не переусердствовать. Особенно, в эпоху развитого DKIM и SPF. Эти две упомянутых технологии вполне себе позволяют предоставить достаточные доказательства того, что письмо отправлено с привязкой именно к тому домену, который указан в качестве “источника”. “Источника” тут в кавычках потому, что схема доставки сообщений электронной почты вообще не подразумевает доменов-источников – источником всегда является ближайший к получателю почтовый релей, который, что называется, “приносит письмо по SMTP”. В этом сила email. И этот же момент приводит к перегибам, с которыми приходится встречаться на практике. Всё дело в разнообразных дополнительных проверках, применяемых SMTP-сервером получателя к SMTP-клиенту, который принёс письмо.

Поэтому переходим к описанию второго способа фильтрации повышенной строгости. Здесь сервер-получатель требует, чтобы все имена MX-ов, указанных для почтового домена отправителя, резолвились (DNS) в маршрутизируемые IP-адреса. Это вот совсем специальный случай, но и он встречается на практике. Что он означает? Вот что: в процессе получения письма сервер получатель отыскивает MX-записи домена-источника в DNS, резолвит их, и если одну из записей не удалось разрезолвить, то не принимает письмо. Тут ключевые слова, обозначающие избыточный уровень фильтрации: “одну из записей”. Представьте, что в зоне домена-отправителя указано три различных имени MX-а. И одно из этих имён, при попытке резолвинга, приводит к ошибке – например, нет такого имени в DNS. Но остались же ещё два! Это полностью допустимая ситуация. У нас же речь о приёме электронной почты. При этом почтовый релей, если бы он доставлял почту в исходный домен, так или иначе должен попробовать использовать другие MX-ы – это прямо предписывается спецификацией, в которой есть даже поле для установки приоритета. И вот с другими MX всё обязательно сработает. Но вот проверять доступность MX-ов в домене-источнике при получении письма – сервер не должен. Но, конечно, технически может и проверить. Главный вопрос тут – как потенциальная недоступность MX в домене-источнике вообще может влиять на приём сообщений? Никак не может, и не должна. Но получается, что влияет.

В только что описанной схеме фильтрации может ещё проверяться состав IP-адресов, полученных в результате резолвинга имён из MX-записей. И если адреса – это какой-нибудь localhost или 0.0.0.0, то письмо, опять же, отбрасывается.

Кстати, с IP-адресами связан, наверное, самый тривиальный, но при этом действенный и допустимый, способ фильтрации – проверить обратную зону: то есть, принимающий сервер видит IP-адрес источника (почта доставляется по TCP), а поэтому может разрезолвить обратную зону (имя хоста по IP-адресу). И вот дальше начинается “серая зона” (игра слов: “серая” может быть “серой” в смысле специальных списков отправителей – это точно знакомо администраторам почтовиков). Сервер может вообще не принимать сообщения от узлов, которые не имеют записи в обратной зоне, а может даже не принимать и от тех, которые представились не так, как записано в обратной зоне (протокол SMTP подразумевает указание сетевого имени подключающегося клиента). Можно всё же принимать сообщения от подобных узлов и складывать их в “Спам”, можно просить прийти через некоторое время ещё раз. Вариантов много. Обратите внимание, что все они основаны на сопоставлении некоторых имён и адресов, записанных как в SMTP-обмене, так и в DNS, и в IP. Почта предоставляет целую пачку способов сравнить разные имена и адреса, сделав выводы о том, является ли данная “корреспонденция” нежелательной. Во многих случаях ранжировать по степени “нежелательности” можно SMTP-сессию, даже не дожидаясь самого письма.

DKIM – позволяет привязать письмо к доменной зоне криптографически, при помощи цифровой подписи. Это весьма строго. Да, для выполнения проверки серверу придётся не только дочитать пришедшее письмо, но ещё и разобрать подписи, найдя ключ в DNS. Это, конечно, оправдывает “скептическое” использование DKIM при приёме сообщений: понятно, что с вычислительной точки зрения – проще прервать SMTP-сессию в самом начале, даже не дожидаясь заголовков с DKIM и самого письма, которое необходимо для вычисления подписи. Есть ещё SPF – этот механизм срабатывает несколько раньше, так как позволяет привязать к доменной зоне непосредственно IP-адрес узла, который приносит сообщения, относящиеся к этой зоне. И DKIM, и SPF, и обратная зона – подразумевают работу с DNS. Поэтому, что касается рисков обработки DKIM, то упасть “почтовик”, как ни странно, может и без чтения письма, и даже до начала полноценной SMTP-сессии – из-за сбоя резолвера (например, при валидации DNSSEC).

Да, существуют продвинутые интерактивные способы защиты от нежелательных сообщений, когда в ответ на принятое письмо отправляется автоматически сгенерированное сообщение с инструкциями о том, как корреспонденту подтвердить свои “добрые намерения”. Легитимный пользователь почтового адреса, – получатель, – при этом исходного письма не увидит до тех пор, пока корреспондент не выполнит требуемый минимум по подтверждению (в нормальных системах достаточно просто ответить на запрос робота пустым письмом). Но это совсем другая история, если сравнивать со строгой фильтрацией по наличию MX и адресных записей в зоне: ошибка тут вылезет при попытке доставки ответного сообщения корреспонденту – если в его домене нет доступных MX-ов. Предсказывать же такую ошибку в ходе приёма, да ещё и отбрасывать сообщения по результату – так себе способ фильтрации.

Заметьте, что упомянутые выше SPF и DKIM уже дают довольно строгое “подтверждение домена”. Оно уж точно строже, чем состав списка MX-ов и, тем более, наличие A-записей.



Комментарии (3) »

Интересная тенденция, прямо связанная с централизацией и сегментацией Интернета. Всё больше стали замечать глобальные проблемы, которые вызваны локальными техническими ошибками крупнейших провайдеров. Казалось бы, сети, похожие на глобальный Интернет, можно выстраивать таким образом, чтобы даже в случае серёзных локальных проблем, происходила плавная деградация глобального сервиса (graceful degradation), а не внезапное падение всего и вся на таком уровне, что даже дежурные инженеры не могут получить доступы, управление и что-то сделать для восстановления.

То есть, с одной стороны – всё больше и больше критических интернет-сервисов заводится во всё меньшее количество провайдеров; с другой стороны – у этих провайдеров не получается обеспечить внутри своих систем ни надёжность, ни плавную деградацию при проблемах. Несомненно, всё ещё много где и надёжность, и схемы деградации, и даже схемы восстановления – выстроены хорошо, поэтому соответствующие локальные аварии так и остаются локальными, они просто не заметны, о них не шумят в СМИ (после того, как восстановят доступ к “облачным” сайтам этих СМИ из редакции, конечно). Однако тенденция другая: потенциально локальные аварии всё чаще архитектурно масштабируются в обратную сторону – в сторону их “глобализации”.



Комментировать »

Cloudflare публикуют разбор причин аварии сервиса DNS-резолвера 1.1.1.1, который некоторое время был недоступен (глобально) 14 июля 2025 года. Краткая причина, как это нередко бывает, – некорректная работа с BGP: ошибочно удалили маршруты к сервису 1.1.1.1 (это, в принципе, было понятно практически сразу). Интересный момент: написано, что после аварийного отзыва штатных маршрутов Cloudflare – анонсировать префикс 1.1.1.0/24 начала AS4755 (Tata Communications India). Но отдельно отмечено, что этот “угон префикса” не был причиной недоступности сервиса. Всё равно – странно.



Комментировать »

Почему-то очередную “кросс-протокольную” атаку под названием Opossum стали в новостных сообщениях называть “атакой на TLS”. Но к TLS эта атака имеет примерно такое же отношение, как автомобиль – к дороге. Причём, сами авторы не утверждают, что это атака на TLS – на сайте она классифицирована как “кросс-протокольная атака десинхронизации на прикладном уровне”, а применима к прикладным протоколам, использующим TLS и напрямую, и “приспособительно” (opportunistic) на одном и том же логическом узле.

О чём тут идёт речь? Существуют протоколы обмена командами и данным, в которых использование TLS встроено в схему протокола. То есть, на верхнем логическом уровне, не сам обмен протокола полностью и прозрачно завернут в TLS (как HTTP в HTTPS, скажем), а TLS можно включить, при наличии возможности, уже в контексте самого протокола – пример: SMTP + STARTTLS. То есть, сеанс в рамках атакуемого протокола обязательно начинается в открытом и незащищённом варианте. Это позволяет атакующему подменить начальные сообщения той или иной стороны, а потом переключить трафик на использование TLS: либо штатными средствами протокола, либо – перенаправив трафик на другой номер порта. Атакующий при этом должен активно перехватывать сетевое соединение, подменять пакеты и прозрачно перенаправлять трафик на разные номера портов. (В исходной публикации, для одного из сценариев, ещё и требуют выполнения атакующей стороной произвольного кода в контексте веб-страницы внутри браузера.)

Так, механизм STARTTLS для SMTP – тут сервер может предложить поддержку TLS в самом начале SMTP-сессии, а клиент, если он поддерживает TLS, может тут же начать переход на защищённое соединение, просигнализировав об этом серверу. Если переход на TLS произошёл, то SMTP-сессия начинается, фактически, заново – пусть и в том же сокете, но уже внутри TLS. Но для SMTP есть и вариант с прямым TLS-подключением, то есть, сразу по TLS на другом выделенном номере порта (например, 587, а не 25). Для осуществления атаки требуется, чтобы на сервере были доступны оба способа подключения – смысл и состоит в “перекидывании” сессии между открытым соединением и подставным TLS-соединением.

Атака Opossum для SMTP предлагает атакующему возможность обмануть клиентскую программу, которая пытается подключиться с использованием STARTTLS: атакующий перехватывает соединение этой программы и отвечает вместо сервера, отправляя собственное серверное SMTP-приветствие и опцию, указывающую на STARTTLS; далее, как только клиентская программа начнёт инициировать TLS-соединение, атакующий перенаправляет начальное TLS-сообщение клиента на выделенный для TLS номер порта легитимного сервера; сервер считает, что это просто прямое подключение TLS и обрабатывает его обычным образом. Получается, что клиент прочитал подставное SMTP-приветствие и подставной список SMTP-опций, а потом начал SMTP-сессию через TLS, что для сервера выглядит обычной новой сессией. Таким образом, контекст на сервере как бы отличается от контекста на клиенте. Насколько это критично с практической точки зрения, особенно, на фоне того, что атакующий мог вообще скрыть поддержку TLS сервером, – отдельный вопрос. Но никакой атаки на TLS тут нет, TLS сработал так, как и планировалось, однако шаги штатного протокола на стороне клиента и на стороне сервера теперь не синхронизированы, из-за вмешательства атакующего – запросы и ответы переставлены на полуход. В публикации Opossum это, что логично, так и называется: “десинхронизация прикладного уровня”.

Opossum atack
(Иллюстрация из исходной работы.)

Как ни странно, но TLS в “приспособительном” режиме возможен, – в теории, – и для HTTP. Этот вариант, впрочем, практически не встречается на веб-серверах: смысл для HTTP – тёмен, а настраивать нужно отдельно. Для случая HTTP последовательность данной атаки другая: атакующий модифицирует запросы, ответы и задерживает TLS-трафик так, что внутри TLS-сеанса оказывается ответ сервера не на легитимный запрос клиента, а на предыдущий запрос, поступивший к серверу от атакующего в открытом виде. TLS-опять же, атака не касается. Но, как и отмечено в исходной работе, все перечисленные атаки возможны потому, что TLS не предоставляет способа аутентифицировать состояние внешнего протокола на стороне сервера и клиента, а аутентифицирует только имена и адреса. Это так. Однако подобная расширенная аутентификация и не входит в модель TLS: несмотря на наличие расширений типа ALPN, TLS работает только на своём уровне. (Кстати, на ALPN описание атаки Opossum как раз ссылается: с ALPN связана вспомогательная часть и предыдущая атака по теме.)



Комментарии (2) »

Let’s Encrypt сообщают, что выпустили первый TLS-сертификат, валидный для IP-адреса. Это сертификат сроком валидности шесть суток, там пустое поле Subject (это важно, если вы всё ещё проверяете сертификаты по Subject), отсутствует ссылка на OCSP, но всё ещё есть ссылка на CRL. IPv6-адрес указан в Subject Alternative Name, вместе с несколькими доменными именами. Часть указанных имён, кстати, имтируют IPv6-адрес, поэтому они аж восьмого уровня. Вообще, максимальная допустимая “глубина” DNS-имён в Let’s Encrypt – десятый уровень.



Комментировать »

Кстати, в продолжение темы “О капчах”. Сейчас картиночные капчи мне попадаются редко (зато от Cloudflare, с кликом на кнопку, то и дело). Тем не менее, пока на “Хабре” была капча, которая хоть как-то работала, в том смысле, что иногда удавалось её пройти, я насобирал небольшую коллекцию особенно “продвинутых” вариантов. Коллекция – ниже.

Вообще, капча сейчас – необходимый инструмент, конечно, тут спору нет, пусть и к сожалению. На dxdt.ru тоже есть довольно простая капча с текстовыми символами – и она не всегда помогает. Проблема в том, что типовые капчи давно научились быстро решать, – те, кому нужно, – и сейчас увлечение сопоставлением картинок местами приобретает какие-то уж совсем замороченные формы. Вот как на скриншотах.

Captcha screenshot

Две капчи. Сопоставление по утилитарному назначению. Да, тут можно догадаться, наверное, методом исключения. Особенно, на картинке справа: медведь вряд ли подходит к кукольной мебели – выбираем радиоуправляемую машинку типа “монста-трак”. Нет? Не сработало?

Captcha screenshot

Ещё две. Я попробовал, будут ли трудности у ChatGPT (GPT-4o) с этими капчами. Левую капчу я разделил на два блока – с чашкой и всё остальное. Показал ChatGPT сперва картинку чашки, спросил, что нарисовано, получил подробный и верный ответ. Потом показал вторую часть (блок картинок с вариантами) и спросил, может ли ChatGPT найти то, что звучит так же, как чашка, при падении (на английском, по привычке, но, думаю, это не важно здесь). GPT-4o справилось примерно за секунду – ответ: все бутылки звучат так же, как чашка.

Капчу, которая справа, про птичьи ноги, я показал в одной картинке, предложив перевести текст с русского и отгадать загадку. Тут ChatGPT сплоховало, объявив ноги сверху – ногами уток (это верно, но слишком узко), а потом предположив, что утка нарисована справа в нижнем ряду (а там вряд ли утка). Но, тем не менее, от ИИ уровня ChatGPT капчи данного типа вряд ли защищают, а вот для человека – трудновато, нужна “экранная лупа”. Впрочем, нельзя исключать вариант, что теперь решение капчи незадачливым пользователем сайта подразумевает помощь ИИ – так сказать, “вайб-капчинг”.

Captcha screenshot

А это уже больше похоже на какой-то тест Роршаха. Видимо, всё же нарисована лягушка. Почему лягушка должна подходить к варану-крокодилу (или что это?), а не к утке, у которой на спине камера от “гугломобиля”? Наверное, опять методом исключения. Дальше – сложнее.

Captcha screenshot

Числа? Похоже, что вверху слева – это 0.

Captcha screenshot

Перечитайте вопрос: чем тут можно писать? Карандашей или мелков – на картинках нет. А на клавиатуре – печатают.



Комментировать »

Dual EC DRBG (“Сдвоенный детерминированный генератор случайных битов на эллиптической кривой”) – нашумевшая схема генератора псевдослучайных чисел, в которой встроен (потенциальный) математический бэкдор. Несмотря на сразу же возникшие подозрения о бэкдоре, эта схема была без проблем стандартизована NIST в 2006-2007 годах и достаточно широко использовалась. Соответствующий стандарт позже официально отозван NIST.

В криптографии постоянно требуются случайные числа. Получение действительно случайных чисел сопряжено с большими проблемами, которые начинаются с того момента, что всякая попытка строго определить и гарантировать случайность значений неминуемо сталкивается с философскими трудностями, корни которых находятся в области интерпретации реальности. Поэтому на практике гарантировать случайность невозможно, но есть различные модели и допущения, позволяющие приблизиться к “строгой случайности” с точки зрения вычислительных возможностей. (Да, есть “квантовые” предложения – но они сугубо теоретические, и тоже подразумевают некоторую модель – модель “квантовой механики”.) Естественно, только из этого не следует вывод о том, что все практические случайные значения предсказуемы, но зато следует другой вывод – о допустимости использования алгоритмических генераторов псевдослучайных чисел: алгоритмов, выдающих такие последовательностей значений, которые вычислительно неотличимы от истинно случайных. (Оставим понятие “истинно случайный” – за скобками, отметив, что, – по современным представлениям, – генератор “истинно случайных” значений должен быть исключительно аппаратным.)

Важнейшей особенностью криптографических генераторов (псевдо)случайных чисел является то, что выдача генератора детерминирована внутри – то есть, выдаваемые значения определяются внутренним состоянием (пояснение от 28/01/26: это только для внешнего наблюдателя генерируемая последовательность выглядит как случайная). Именно этот аспект служит фундаментом для построения бекдора в Dual EC DRBG. Криптографические генераторы псевдослучайных чисел имеют важнейшее значение не только для теоретической, но и для прикладной криптографии – это краеугольный камень всех практических систем криптографической защиты.

Несмотря на то, что с точки зрения теории криптографии схема, о которой идёт речь, предоставляет потенциальный бэкдор, её свойства можно трактовать и как инструмент “депонирования” ключей – то есть, при реализации конкретного экземпляра генератора выбираются такие параметры, что уполномоченная сторона может его “взламывать”. Однако уже сам факт того, что возможно провести в статус стандарта такую схему генератора, которая содержит механизм построения бэкдора на уровне алгоритма и описание этого бэкдора опубликовано на момент стандартизации, имеет большое историческое значение. Ещё более показательна и интересна сугубо математическая часть данного бэкдора. Настоящая статья посвящена именно математике бэкдора и в деталях объясняет то, почему он работает.

По сути, бэкдор в Dual_EC_DRBG – это реализация протокола Диффи-Хеллмана (DH) на эллиптической кривой: секретный ключ находится у стороны, контролирующей бэкдор через параметры протокола, что позволяет этой стороне получать внутреннее состояние генератора псевдослучайных чисел, наблюдая его выдачу. Знание внутреннего состояния приводит к раскрытию всей последующей выдачи генератора. При этом, математически, пользователь Dual EC DRBG неявно выполняет обмен DH с контролирующей параметры генератора стороной. Это важное свойство штатных схем построения “надёжных бэкдоров”: доступ к бэкдору должен быть только у той сторны, которая знает секретный параметр – секретный ключ. Есть и другое важное свойство: если секретный параметр не был раскрыт, то строго доказать, что бэкдор действительно встроен в конкретную реализацию – нельзя. Это не отменяет возможности тсрогого описания для механизма такого бэкдора.

Итак, в Dual EC DRBG, без знания секретного параметра раскрыть внутреннее состояние генератора вычислительно трудно, потому что базовые функции протокола – односторонние. Поэтому, если оставить за скобками секретный параметр, то протокол полностью соответствует общепринятой схеме.

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

Scheme, DRNG

На схеме: Sn – внутренние состояния генератора; φ() – функция, преобразующая состояние Sn в Sn+1; ξ() – функция, преобразующая состояние Sn в выдачу генератора Bn на данном шаге. Биты пошаговой выдачи Bn могут конкатенироваться для получения псевдослучайной последовательности нужной длины (на схеме: RND[…]) – это типовой способ прикладного использования генератора.

Криптографические генераторы псевдослучайных чисел, помимо общих “статистических” требований к неотличимости выдачи от случайной, имеют ряд особенностей. Прежде всего – выдача должна быть необратимой. А именно: состояния Sn являются секретными параметрами, поскольку позволяют раскрыть будущую выдачу генератора. При этом выдача генератора (Bn) на каждом шаге – публична. Из этого нетрудно сделать вывод, что функции φ и ξ должны быть односторонними (однонаправленными – по значению сложно определить аргумент): если это не так, то по публично доступным данным (Bn) легко вычислить состояние генератора. В чём и состоит логический смысл описываемого бэкдора.

Почему односторонней должна быть и функция φ, которая переводит текущее внутреннее состояние в следующее? Это нужно для того, чтобы по утекшей информации о внутреннем состоянии на каком-то шаге было вычислительно сложно восстановить предыдущую выдачу генератора. Одно из базовых требований к криптографически стойким генераторам псевдослучайных чисел состоит в минимизации возможностей по раскрытию данных. Например, если есть бэкдор, позволяющий обратить ξ, то, при условии обратимости φ, взяв любую точку можно раскрыть сколько угодно данных – и предыдущие, и следующие. При этом обратимость ξ может являться следствием не бэкдора, а обычной уязвимости, в том числе, уязвимости реализации алгоритма. Предположим, эта уязвимость ξ срабатывает лишь на каких-от редких данных: соответственно, если подобрать такие данные удалось, но φ осталась необратимой, атакующий сможет вычислить только следующие состояния генератора и все предыдущие секреты останутся защищены.

Математической особенностью описываемого бэкдора является то, что он вовсе и не позволяет обратить функции ξ и φ – они остаются односторонними, но бэкдор открывает возможность простого вычисления следующего внутреннего состояния генератора по известной выдаче ξ. Это возможно потому, что алгоритм содержит дополнительную структуру, связывающую функции ξ и φ.

Псевдослучайная выдача в криптографических протоколах постоянно используется в открытом виде. Например, в открытом виде передаются векторы инициализации для схем зашифрования (GCM и пр.), псевдослучайные векторы в сообщениях TLS (поля ClientRandom и ServerRandom) и др. Поэтому нетрудно извлечь значения из трафика, сопоставить их с выдачей генератора псевдослучайных чисел, раскрыть внутреннее состояние генератора и получить последующие биты выдачи, которые, например, были использованы тем же приложением для получения секретных ключей шифров, защищающих трафик – это позволит восстановить секретные ключи и расшифровать трафик в пассивном режиме.

Dual EC DRBG работает на эллиптической кривой (над конечным полем), а в качестве односторонних функций использует умножение точки эллиптической кривой на скаляр: x∘P. Далее умножение на скаляр обозначается “блобом” (∘). Стойкость к обращению здесь основана на задаче дискретного логарифмирования: то есть, по значению Q = x∘P – вычислительно трудно найти x.

Вспомним, что умножение на скаляр – обычное для эллиптической криптографии последовательное сложение точки кривой с самой собой. Сложение – операция, которая введена на точках кривой. А именно: точкой кривой называется пара (X, Y) значений “координат”, соответствующих уравнению кривой. Здесь X и Y – это элементы подлежащего конечного поля, которое входит в параметры криптосистемы. В данном конкретном случае (например, для кривой P-256) используемое конечное поле – это вычеты, то есть “остатки” по модулю простого числа. Сложение точек P + Q = R позволяет по паре координат точки Q (XQ, YQ) и паре координат точки P (XP, YP) Получить координату точки R (XR, YR). Скаляр – это целое число. Умножение на скаляр 3 означает, что точка складывается сама с сбой в трёх экземплярах: 3∘P = P + P + P (плюс – это сложение точек). По такому сложению точки всякой эллиптической кривой всегда образуют группу (по определению эллиптической кривой).

В алгоритме Dual EC DRBG используется две точки кривой: P и Q. Точка P – задаёт последовательность внутренних состояний. Внутреннее состояние Sn в Dual EC DRBG – целое число, которое соответствует координате X точки кривой, полученной умножением P на значение предыдущего состояния, как на скаляр. Вторая точка, Q – задаёт “ответвления”, то есть, выдачу генератора по каждому из состояний, и используется в качестве основания на каждом шаге. Ниже представлена упрощённая схема Dual EC DRBG.

Scheme, DRNG

На этой схеме: Sn – внутреннее состояние; для получения следующего состояния из текущего – точка P умножается на значение состояния (скаляр: Sn∘P), а координата X получившейся точки – выводится в качестве нового состояния генератора; для вывода случайных значений – вторая точка, то есть – точка Q, умножается на состояние (Sn∘Q) и выводится координата X получившейся точки. То есть, используется две одинаковых функции с разным основанием: P и Q. Раз стойкость этих функций основана на дискретном логарифмировании, то они односторонние, как и требуется.

Математический смысл бэкдора не нарушает стойкость конкретных операций с точками P и Q, он несколько хитрее и строится на в соотношении между точками P и Q. Допустим, атакующей стороне известно такое значение δ, что P = δ∘Q. Выдача генератора – это X-координата точки Sn∘Q. Атакующий находит подходящую Y-координату, подставив значение в уравнение кривой (точек с подходящими координатами будет две, алгоритм знак координаты Y не различает, но выбор точки, очевидно, не представляет труда). Таким образом атакующий легко восстанавливает точку кривой, подходящую для выдачи генератора. Далее – умножаем на δ.

δ∘(Sn∘Q) = Sn∘(δ∘Q) = Sn∘P   (1)

Рассмотрим формулу (1) подробнее. Почему она работает? Потому что скаляры – это целые числа. Из-за коммутативности группы точек кривой к скалярам применимы арифметические свойства целых чисел. В алгебре такая конструкция называется ℤ-модулем. Всякая коммутативная группа является ℤ-модулем. (Некоторые алгебраисты из-за этого даже не считают коммутативные группы “настоящими” группами.) Применительно к эллиптической кривой: 3∘P = P + P + P, а 5∘P = P + P + P + P + P. Но тогда (3+2)∘P = 5∘P = P + P + P + P + P, что следует из свойств групповой операции – просто поставим скобки: (P + P) + (P + P + P), получив, таким образом, две точки (P + P) = 2∘P и (P + P + P) = 3∘P. 3∘P + 2∘P = 5∘P. Обратите внимание, что здесь знак “плюс” используется в двух значениях: и для обозначения сложения точек кривой, и для обозначения привычного сложения в целых числах (3+2). А раз схема работает для сложения целых чисел, то она обязательно работает и для умножения целых чисел, потому что умножение в целых числах можно построить через сложение (собственно, при корректном преобразовании 0 и 1, сложение и умножение в целых числах просто могут быть переведены одно в другое, как операции). Но тогда и (3*2)∘P = (P + P) + (P + P) + (P + P) = 3∘(2∘P) = 6∘P. Что и используется в формуле (1), вместе с коммутативностью умножения в целых числах: 2 * 3 = 3 * 2.

Таким образом, атакующая сторона, которая знает секретный скаляр δ, получила значение следующего состояния генератора, вычислив Χ-координату точки Sn∘P (см. схему). Формула (1) вообще очень похожа на реализацию протокола Диффи-Хеллмана (DH) на эллиптической кривой. То есть, пользователь генератора псведослучайных чисел, можно сказать, обменялся с атакующей стороной открытыми параметрами Диффи-Хеллмана. А именно: открытый параметр атакующей стороны, статический ключ, зашит в константы протокола – P = δ∘Q, где секретный ключ – δ; открытый параметр DH пользователя – это динамическая выдача основного алгоритма – Sn∘Q, где секретный ключ Sn. “Открытые параметры DH” пользователя атакующая сторона наблюдает в трафике. Важное отличие от практического DH состоит в том, что “общий секрет” тут не должен становиться “общим” с атакующей стороной.

Итак, для внедрения бэкдора нужно выбрать такие P и Q, что P = δ∘Q. Полученные точки – это параметры конкретной реализации алгоритма, но они могут быть закреплены в стандарте (что и было сделано). Но в спецификации Dual EC DRBG для кривой P-256 в качестве точки P строго указана базовая точка группы кривой, которая используется в спецификации P-256. То есть, произвольно выбрать P нельзя. Оказывается, в том случае, если одна из точек P или Q заранее строго задана, то определить нужное значение δ можно при помощи вычисления мультипликативного обратного по модулю порядка группы точек. Важно, чтобы порядок был простым числом. Но это стандартная практика для прикладной криптографии. Например, для кривой P-256 – соответствующий порядок простой.

Чтобы получить бэкдор, нужно определить δ из P = δ∘Q. Может показаться, что если точка P зафиксирована, – соответственно, выбрать эту точку умножением какой-то точки Q на произвольный скаляр нельзя, – то требуется решить сложную задачу отыскания дискретного логарифма. Но это не так, поскольку мы всё равно можем выбрать произвольную точку Q. Чтобы согласовать точки, возьмём произвольное значение ε в интервале от 2 до порядка группы, генерируемой P, а потом возьмём δ = ε^(-1) по модулю порядка. Пусть порядок P – то есть, количество точек в используемой группе, – это простое число n. Тогда нужно найти ε * δ = 1 (mod n). (Например, 2 – обратный по умножению элемент к 4 по модулю 7, так как 2 * 4 = 1 (mod 7).) Задача нахождения мультипликативного обратного по модулю простого числа здесь вычислительно несложная. Определив δ = ε^(-1), в качестве точки Q выберем ε∘P. Тогда: δ∘Q = δ∘(ε∘P) = (ε^(-1)*ε)∘P = P. Следовательно, мы нашли такое δ, что P = δ∘Q.

То есть, если можно выбрать оба параметра – точки P и Q, – то выбираем так, что P = δ∘Q, а если одна из точек зафиксирована – выбираем δ = ε^(-1) по модулю (простого) порядка группы точек, это всегда можно сделать из-за особенностей спецификации: подлежащие группы имеют простой порядок. (Не забывайте, что в формулах выше используется два умножения – умножение точки на скаляр и умножение целых чисел (δ = ε^(-1); 1 = ε^(-1)*ε). Это работает потому, что скаляры – целые числа, но по модулю порядка группы.)

В Dual EC DRBG битовый вывод генератора, – то есть, X-координата Sn∘Q, – урезается: из него удаляются 16 старших битов. Это означает, что прямо использовать результат для вычисления координат исходной точки нельзя. Но 16 бит можно быстро перебрать, проверяя, для всех значений подряд, лежит ли на кривой точка с соответствующей X-координатой. Вычисление значений по уравнению кривой тоже не составляет проблемы – уравнение известно, а используемые там операции обязательно быстрые.

Естественно, полученная перебором точка может оказаться неверной. То есть, точка не будет являться Sn∘Q. На этом шаге “через бэкдор” у атакующего нет никакого способа проверить, что точки совпали. Но это не сильно затрудняет атаку. Значения секретного состояния нужно вычислить для всех возможных точек, которые соответствуют сокращённому битовому значению, а результат по каждой точке – сопоставить с дальнейшим анализом трафика. Например, если выдача генератора используется для получения секретного ключа, то выбрать его верное значение можно при помощи пробного расшифрования. В любом случае, анализ 2^16 числовых значений при помощи перебора не представляет здесь вычислительной проблемы.

В ранней версии стандарта NIST на Dual EC DRBG реализация использовала подмешивание дополнительной маски на каждом шаге вычисления псевдослучайных чисел. Это делало описанный бэкдор нерабочим. Однако стандарт был быстро обновлён, точка подмешивания дополнительной маски перенесена, и использование бэкдора стало снова возможным. Поэтому данная особенность здесь не рассматривается.

Проблема алгоритма Dual EC DRBG, как криптографического генератора псевдослучайных чисел, помимо низкой производительности, в том, что внутри его конструкции есть жесткая структура, зависящая от внешних параметров. Из-за алгебраических свойств эллиптических кривых, в практической реализации – точки P и Q всегда связаны. Да, иногда, если специально постараться, они могут быть получены способом, дающим некоторую гарантию того, что связующий скаляр никому не известен. Либо, P и Q может генерировать конкретный пользователь, в качестве параметра для своей локальной версии генератора. Стандарт NIST разрешал такой вариант, но не рекомендовал его, а для соответствия строгим требованиям FIPS допускались только параметры из спецификации.

(Это расширенная версия статьи, которую я недавно опубликовал на “Хабре”.)



Комментировать »

Зайти в аккаунт на “Хабре” теперь можно только тогда, когда сделать это разрешил “Яндекс” (см. скриншот). Но в моей конфигурации браузера и ОС капча от “Яндекса” не работает – вероятно, потому что не устанавливаются какие-то куки и, – вполне специально, – отключены запросы к каким-то серверам “Яндекса” на моей стороне (я проверил, что дело именно в сетевых настройках, воспользовавшись другой конфигурацией). Что ж – видимо, не нужно больше на тот “Хабр” заходить, раз там так сделали, что у них “Яндекс” в роли регулятора (казалось бы – профильный “ИТ-ресурс”, но нет).

Screenshot



Комментарии (4) »

Сколько лет Интернету – вопрос многогранный. Дмитрий Бурков пишет, что отсчитывать годы нужно с момента разработки BGP (и это довольно логично, так как BGP в современной Сети используется для обмена информацией о маршрутах доставки пакетов).



Комментировать »