Существенная часть информации о TLS-соединении доступна системам инспекции трафика (DPI). Чаще всего, конечно, упоминается поле SNI (Server Name Indication), в котором передаётся имя сервера. Для маскировки SNI в TLS 1.3 уже предложен дополнительный механизм Encrypted SNI.

Версии TLS ниже 1.3 подразумевают передачу серверных TLS-сертификатов в открытом виде (на начальном этапе установления соединения). В состав сертификата входят и имена сервера (может использоваться несколько), и открытый ключ сервера. Открытый ключ так же идентифицирует сервер, однако в некоторых случаях один и тот же ключ может использоваться с разными именами. Серверный сертификат является важным признаком классификации TLS-соединений, с другой стороны, сертификат имеет существенный размер и требует наличия в составе DPI-системы функций, которые могут разобрать сертификаты по полям и проанализировать – всё это заметная дополнительная вычислительная нагрузка, особенно, если соединений много.

В открытом виде (версии меньше 1.3) на начальном этапе передаются и клиентские сертификаты, которые в TLS используются для аутентификации клиента сервером. Клиентские сертификаты часто применяются в решениях VPN, соответственно, анализ клиентского сертификата во многих случаях позволяет точно распознать начало VPN-соединения.

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

Особенно мощная система DPI может вести статистику соединения: в TLS-трафике присутствует открытая последовательность TLS-записей, поэтому анализирующая поток данных система видит размеры записей, а также их типы. Здесь, опять же, существенный шаг вперёд проделан в версии TLS 1.3. А именно: реальные типы записей в TLS 1.3 скрыты – виден только “исторический” тип Application, назначаемый всем записям в фиктивном заголовке, это делает поток типов однородным, полностью убирая важный источник метаданных для классификации трафика. В более ранних версиях TLS типы записей передаются в открытом виде, так что анализатор потока может обнаружить состояние TLS-сеанса (так как протокол использует записи разных типов для передачи сигналов, сообщений об ошибках и пр.)

DPI видит длину отдельных TLS-записей. Однако TLS позволяет приложению разными способами маскировать реальную длину передаваемых данных. А в TLS 1.3 имеется специально для этой цели предназначенный механизм на уровне защищённого транспорта: длина записей может выравниваться с помощью дополнения. Это означает, что реализация в версии 1.3, минимизирующая утечки метафинформации, может превратить поток данных в последовательность TLS-записей одинакового типа и одинаковой длины – DPI будет сложно за что-то зацепиться.

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

Естественно, хорошо защищённый протокол должен свести к минимуму утечки метаинформации. Это, частично, уже сделано в TLS 1.3, однако TLS является весьма универсальным протоколом, который, к тому же, проектировался с учётом повышения его эффективности в роли транспорта для массовых соединений, а не как протокол, скрытый от DPI. Поэтому пассивные анализаторы трафика всё ещё получают из TLS-соединения дополнительную информацию об узлах и состоянии приложений (дополнительную – по сравнению, например, с информацией уровня TCP, к которой относятся адреса узлов, номера портов, порядок и размер TCP-пакетов и др.). Методы криптографии позволяют спроектировать хорошо замаскированный протокол, но каждый шаг маскировки снижает эффективность, в частности, увеличивает затраты на установление соединения (это перебор адресов, генерация дополнительных секретов и т.д.). Тем не менее, ситуация тут такова, что даже небольшой, но верно спланированный шаг маскировки – существенно затрудняет работу DPI. В ряде случаев, рост “сравнительной сложности” на стороне DPI оказывается, как минимум, экспоненциальным: представьте, что специальный протокол использует перемешивание UDP-пакетов разных потоков, отправляемых по различным адресам серверов.



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

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

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

Скрытый протокол, по условиям задачи, должен работать на базе распределённой сети и не требовать строгого центрального управления всеми узлами при обмене сообщениями. Это обусловлено риском компрометации такого “центра управления”, а также тем, что центральный вариант гораздо более уязвим к сегментации сети (да, есть варианты с автоматическим выбором нового “центра” и так далее, но мы пока просто примем, что протокол использует распределённую сеть).

Сразу же возникает вопрос о транспорте данных (может быть, этот транспорт – TCP?), но так как мы практически сразу столкнёмся с необходимостью стеганографии и маскировки узлов, то с транспортом всё окажется не так просто, поэтому конкретный протокол в условия задачи не включаем, оговорим только, что “какой-то транспорт” между “какими-то узлами” должен быть доступен.

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

Итак, какими свойствами и механизмами должен обладать скрытый протокол в таких (весьма жёстких) условиях?

1.

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

2.

Для сокрытия трафика необходимо использовать стеганографию. В принятой модели угроз, если один из узлов просто передаёт зашифрованное сообщение вне прочих сеансов, то этот факт тут же оказывается обнаружен. Стеганографический канал маскирует сеанс обмена сообщениями под трафик другого типа. Это означает, что протокол не может прямо использовать привычные виды транспорта, а должен подразумевать наличие дополнительного трафика. Простой пример: сообщения могут быть скрыты внутри текстов веб-страниц и веб-форм, в качестве базового трафика используется имитация работы с веб-сайтом. В данном случае, веб-трафик может передаваться по TCP или UDP, с использованием TLS/HTTPS или QUIC, экзотические варианты вместо веб-трафика используют непосредственно TLS, или даже служебные заголовки IP-пакетов и DNS, всё это не так важно для стеганографии. Важны достаточный объём данных и наличие симметричных ключей, позволяющих организовать стойкий стеганографический канал. При наличии ключей – такой канал организовать всегда можно. (Ключи используются для задания псевдослучайной последовательности, которая необходима для работы механизма встраивания скрытых данных в поток трафика.)

3.

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

4.

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

5.

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

Несмотря на существенные сложности, хорошо скрытые протоколы можно разработать, а также и реализовать. Но они настолько отличаются от используемых сейчас, например, в распространённых мессенджерах, что быстрого внедрения ожидать не приходится.



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

Подробное описание того, как работает (на практике) технология ESNI (зашифрованное поле SNI TLS), в текущей draft-версии. В качестве примера я использую тестовый сервер tls13.1d.pw, где ESNI поддерживается (а поддерживающий браузер – это Firefox свежих версий, но ESNI там нужно включить, вместе с DNS-over-HTTPS).

Введение

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

TLS-сервер, поддерживающий ESNI, должен уметь распознавать расширение ESNI в составе сообщения ClientHello и обрабатывать его, проверяя корректность. Кроме того, сервер должен отправить ответную, серверную запись ESNI. В этой записи содержится копия значения, полученного в зашифрованном виде от клиента. ESNI-ответ сервера так же передаётся в зашифрованном виде.

Логика работы следующая: браузер получает из DNS открытый ключ DH (протокола Диффи-Хеллмана), генерирует сеансовый симметричный ключ, зашифровывает имя сервера и некоторое уникальное значение, которые, вместе со своим открытым ключом DH, передаёт серверу в расширении ESNI ClientHello. (Я описывал этот процесс в отдельной записке.)

Часть DNS

Сейчас в качестве DNS-записи используется запись типа TXT. Возможно, в дальнейшем для ESNI выделят новый тип записи.

Структура записей, размещаемых в DNS, следующая (в нотации языка Go):

type KeyShare struct {
Group uint16
Key []byte
}
type ESNIKeys struct {
Version uint16
Checksum [4]byte
Keys []KeyShare
Ciphers []uint16
PaddedLength uint16
NotBefore uint64
NotAfter uint64
Extensions []byte
}

Данные кодируются в Base64 и публикуются в TXT-записи под именем, содержащим префикс _esni. Для tls13.1d.pw это _esni.tls13.1d.pw. Сейчас для tls13.1d.pw опубликована ESNI-запись с двумя ключами (X25519 и P-384).

Подробные описания полей:

Version

длина: два байта; значение: 0xFF01 (действующая версия, draft).

Checksum

длина: четыре байта; это контрольная сумма – первые четыре байта значения SHA-256 от всех данны структуры ESNI (для вычисления контрольной суммы поле Checksum во входных данных заполняется нулями).

Keys

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

Рассмотрим список ключей для ESNI-записи _esni.tls13.1d.pw (здесь используется два ключа – X25519, P-384):

длина списка: 0x0089;

тип первой криптосистемы (X25519): 0x001D;
длина записи ключа (32 байта): 0x0020;
значение ключа: […] /32 байта, в криптосистеме X25519 – ключи записываются 32-байтовыми последовательностями/;

тип второй криптосистемы (P-384): 0x0018;
длина записи ключа (97 байтов): 0x0061;
значение ключа (97 байтов): 0x04[…] /ключ является точкой на кривой, записываются координаты точки, первый байт обозначает тип представления (04 – несжатое), далее – две координаты по 48 байтов: 48 + 48 +1 = 97; 48 байтов – соответствуют разрядности криптосистемы).

Ciphers

это тоже список, длина зависит от количества поддерживаемых шифров. Для tls13.1d.pw используется один шифр:

длина списка: 0x0002 (два байта – идентификатор шифра);
идентификатор шифра (AES_128_GCM): 0x1301.

PaddedLength

два байта, поле содержит максимальную длину записи списка имён в ESNI, значение, которое поддерживает сервер tls13.1d.pw: 0x0080.

NotBefore, NotAfter

всем привычные таймстемпы по восемь байтов. Интервал валидности записи.

Extensions

расширения ESNI. Они пока не определены спецификацией. Поле является списком, соответственно, пустой список представляется двумя нулевыми байтами (список, имеющий длину нуль): 0x0000.

Часть TLS

Обработка ESNI TLS-сервером, который действует на tls13.1d.pw, проводится при получении ClientHello. Это сообщение содержит список расширений, для каждого расширения указывается тип (подробнее про то, как работает TLS можно почитать в техническом описании протокола). Тип расширения ESNI – 0xFFCE (это Draft-версия!). Внутренняя логика обработки: расширения передаются в виде списка TLS-структур, длина списка задаётся первыми байтами, далее идут типы расширений и соответствующие им поля данных, каждое поле начинается байтами, содержащими длину.

Например, вот тип, описывающий клиентское расширение ESNI (представление внутри сервера):

type TLS_ESNI struct{
Cipher uint16
Group uint16
KeyShare []byte
Digest []byte
Data []byte
}

Клиент передаёт в ESNI идентификатор шифра (Cipher), тип криптосистемы (Group) и свой ключ DH (KeyShare), а также контрольную сумму (Digest) и, собственно, полезные данные (Data) – nonce и зашифрованное имя сервера. Значение nonce (16 байтов) – это то самое значение, которое сервер должен передать в ответном ESNI-расширении.

При разборе полей KeyShare, Digest, Data – используется обычный для TLS подход: первые два байта интерпретируются как длина записи, далее, в зависимости от типа, аналогичным способом разбираются поля данных.

Конкретно в моём тестовом сервере обнаружение и обработка ESNI устроены так: на первом шаге читаются поступившие TLS-записи, делается попытка разобрать их по TLS-сообщениями и построить список таких сообщений, если попытка удалась, то в списке выполняется поиск ClientHello; если удалось найти ClientHello, то для него вызывается парсер, который разбирает сообщение, выделяя “голову” и список расширений (здесь речь про все расширения, не только про ESNI); на втором шаге – делается попытка в списке расширений ClientHello найти расширения, необходимые для сессии TLS 1.3 (SupportedVersions и др.), это позволяет распознать нужную версию протокола; если минимальный набор расширений найден, то делается попытка обнаружить расширение ESNI. И, соответственно, если расширение обнаружено, то оно передаётся парсеру ESNI, который разбирает его по полям. Далее, используя секретный ключ для ESNI, сервер, выполняя алгоритм DH, вычисляет симметричный ключ и пытается расшифровать данные (поле Data). Если расшифрование завершилось успешно, то заполняется структура с данными из ESNI и генерируется ответное серверное расширение. (Отмечу, что это логика работы, подходящая именно для тестового сервера.)

Если возникли какие-либо ошибки в обработке ESNI, то, в действующей версии сервера, TLS-соединение завершается (с ошибкой уровня TLS). Здесь для ESNI получилось исключение, потому что многие другие ошибки и несоответствия сервер специально игнорирует, чтобы показать на странице результатов сведения об этих ошибках; наиболее существенный пример – это значение Finished клиента: некорректное значение, вообще говоря, является фатальной ошибкой, но тестовый сервер его игнорирует, выводя, впрочем, пометку (воспроизвести эту ситуацию довольно сложно – потребуется специальная утилита на стороне клиента). В дальнейшем я планирую сделать такую же мягкую обработку ошибок и для ESNI. Как минимум, наличие дефектного расширения ESNI не должно считаться фатальным.

Успешно расшифрованное имя из ESNI используется сервером, собственно, оно просто позже выводится на страницу результатов. Расшифрованное значение nonce – сервер записывает в ответное ESNI-сообщение. На этом обработка ESNI заканчивается. Если же расширение ESNI не обнаружено, то сервер продолжает обрабатывать соединение по обычной схеме. Все сообщения можно посмотреть на веб-странице, которую выводит сервер.

Да, кстати, из недавно добавленных улучшений на tls13.1d.pw: сейчас там выводятся симметричный ключ и вектор инициализации ESNI.



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

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

Внешний сканер, которому не известен подходящий секрет, не может отличить обычный веб-узел от веб-узла со скрытым сервисом, так как даже если сканер пытается передать некоторую имитацию запроса к скрытому сервису, в ответ он получит лишь сообщение об ошибке – одинаковое и для узла со скрытым сервисом, и для обычного веб-узла. Прикрытием, в случае HTTPS, может служить любой сайт, например, какой-нибудь тематический сайт, сайт-справочник и так далее. HTTPS удобен потому, что это один из самых распространённых протоколов, кроме того, он использует TLS, а это позволяет прозрачно провести аутентификацию узла. Есть черновик RFC, в котором описан именно этот подход.

Сходную схему можно построить и на уровне TLS (но, опять же, применительно к веб-узлу). Например, так (ниже – копия моего текста, который я некоторое время назад публиковал в Facebook).

Используем TLS, поверх которого работает HTTPS на некотором сервере: то есть, это 443/tcp и всё должно выглядеть как веб-сервер для внешнего сканера. Для упрощения, считаем, что у нас TLS 1.3, вообще, это не так важно, но 1.3 подходит лучше.

В TLS, при установлении соединения, передаются специальные сообщения. В них есть разные поля, мы будем использовать те, которые предназначены для отправки (псевдо)случайных данных – клиентская пара: ClientRandom и SessionID, серверная – ServerRandom и SessionID (значение не изменяется). Оба поля, в общем случае, содержат 32 байта данных (там есть всякие ограничения, но мы будем считать, что их нет). Цель – получить наложенный протокол, который активируется внутри TLS-трафика и только при наличии некоторых ключей, а в прочих случаях – неотличим от HTTPS/TLS. Механизм следующий.

Конфигурация: сервер, реализующий веб-узел – показывает произвольный сайт, например, трансляции новостей; клиент, планирующий использовать скрытый сервис (прокси), подключается к серверу по 443/tcp через TLS.

Клиент знает определённые ключи: общий с сервером симметричный ключ Ck (пусть, 256 бит; это ключ только для конкретного клиента – на сервере ведётся реестр ключей по клиентам, см. ниже), публичный асимметричный ключ сервера Pk (может отличаться от ключа, используемого сервером в TLS; считаем, что это та или иная криптосистема на эллиптической кривой, поэтому ключ тоже 256-битный, в совсем уж технические детали я постараюсь не вдаваться). На первом этапе клиент должен передать серверу свой идентификатор (некоторое число), который позволит серверу найти на своей стороне соответствующий секретный симметричный ключ (копию Ck).

Клиент, устанавливая TLS-соединение, использует серверный ключ Pk (он должен быть известен заранее – это важно) для получения общего секрета протокола Диффи-Хеллмана (DH), вычисленную открытую часть DH клиент отправляет в поле ClientRandom, а на основе полученного секрета – генерирует сеансовый симметричный ключ (Tk) и зашифровывает свой идентификатор, который, в зашифрованном виде, записывает в поле SessionID.

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

К этому моменту, клиент уже может перейти на защищённый обмен сообщениями на уровне TLS (согласно спецификации). Клиент аутентифицирует сервер средствами TLS. Если аутентификация прошла успешно, то клиент переходит к следующему шагу получения доступа к скрытому сервису (если нет, то клиент просто закрывает TLS-сессию). На основе ответа сервера, клиент вычисляет вторую итерацию DH (это DH для скрытого сервиса) – получает второй общий секрет DH_2, используя ServerRandom, и второй открытый параметр DH_s, который нужно передать серверу (см. ниже). Итак, клиент, на настоящий момент, аутентифицировал сервер и получил следующие (дополнительные) криптографические параметры: общий секрет DH_2, сеансовый симметричный ключ Tk, общий с сервером симметричный ключ Ck. На основе этих значений, используя ту или иную хеш-функцию (например, SHA-256), клиент генерирует секретный тег (256-битное значение). Клиент соединяет это значение с параметром DH_s и записывает в начало полезной нагрузки первого TLS-сообщения, это, условно говоря, magic number. Полезная нагрузка передаётся в зашифрованном виде, поэтому третья сторона тег (magic number) – не видит.

Сервер, получив TLS-сообщение, расшифровывает его штатным образом, интерпретирует начальные данные как тег, выделяет DH_s, вычисляет общий секрет DH_2, генерирует ключи (секретный ключ Ck, соответствующий клиенту, сервер определил ранее – теперь этот ключ пригодился), вычисляет значение хеш-функции и сравнивает результат с тегом. Если значения совпали, то сервер считает, что осуществляется доступ к скрытому сервису и начинает проксировать полезные данные TLS в сторону этого сервиса (там уже есть своя аутентификация и пр.) Если тег не совпал, то сервер вспоминает, что он является веб-сервером с HTTPS и отвечает обычной (подходящей) HTTP-ошибкой, так как подставной тег выглядит как неверный HTTP-запрос.

Посмотрим, что видит третья сторона, пассивно просматривающая трафик: третья сторона видит, что установлено TLS-соединение на 443/tcp (HTTPS) и узлы обмениваются информацией по TLS, внутрь заглянуть нельзя, так что проксируемый трафик не виден. Так как, при правильно выбранной криптосистеме, значения ClientRandom, ServerRandom и SessionID вычислительно неотличимы от случайных (но при этом реально являются параметрами DH и зашифрованным идентификатором), то никаких подозрений, сами по себе, вызвать не могут.

Что видит активная третья сторона, проводящая сканирование узлов? Такой сканер не знает клиентских ключей, поэтому, даже попытка имитировать доступ к скрытому сервису, путём записи произвольных значений в поля TLS-заголовков и в данные сессии – будет приводить к ошибке HTTP (либо к ошибке TLS). Понятно, что обычное HTTPS-сканирование показывает, что там какой-то веб-сайт. Таким образом, узел, реализующий скрытый сервис, неотличим от обычного веб-узла с HTTPS. Более того, если сканеру известна часть ключей, например, открытый ключ сервера Pk, то сканер всё равно не сможет сгенерировать корректный тег, так как должен для этого знать ещё и валидный клиентский ключ. До момента появления корректного тега сервер ведёт себя в точности как HTTPS-узел, поэтому, опять же, не отличается от обычного сайта.

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

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



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

По адресу http://hold-my-beer.xyz/ (да, он несколько странный, но правильный) – я разместил веб-интерфейс экспериментального сервиса, который пытается определить, поддерживает ли ваш DNS-резолвер валидацию DNSSEC. Довольно давно я уже сделал сервис, проверяющий поддержку DNSSEC при помощи браузера. Отличие нового эксперимента в том, что здесь проверка происходит также и на серверной стороне, а в браузер передаются адреса резолверов – как они видны на авторитативных серверах. То есть, методика измерения совсем другая, более полная, так как позволяет собирать статистику. Но, повторюсь, это пока эксперимент.

Для проверки – достаточно зайти браузером по ссылке. Там есть и визуальный “флаг”, который покажет, поддерживается ли валидация DNSSEC (вверху страницы, зелёный/красный). Сразу оговорю технический момент, связанный с сервисом резолвера Google Public DNS (8.8.8.8): этот сервис заявлен как валидирующий, но в случае данного теста – браузер покажет, что поддержки DNSSEC нет. И это действительно так. Причина в том, что для теста используются имена (DNS-зоны) четвёртого уровня и ниже, и здесь сервис Google почему-то не проводит валидацию (возможно, так задумано, возможно – это ошибка: нужно будет написать в Google). При использовании, например, Cloudflare (1.1.1.1) – всё работает нормально, как ожидается.

http://hold-my-beer.xyz/

(Это временный сервис, точнее – демонстратор технологии.)



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

Открытый сервис DNS-резолвинга 1.1.1.1 от Cloudflare, оказывается, реализует QNAME Minimization – это метод, снижающий утечку через DNS информации о посещаемых узлах, я описывал его несколько лет назад.

Интересно, что у 1.1.1.1 сейчас реализованы все инструменты защиты DNS: DNS-over-TLS, валидация DNSSEC (более строгая, чем у Google Public DNS), QNAME Minimization. В случае с последней технологией, использование TLS, само по себе, не закрывает утечку, так как без “минимизации” – информация о полном имени уходит на все авторитативные серверы, присутствующие в цепочке.



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

Про технологию ESNI (и SNI) я не так давно написал несколько записок. Сейчас ESNI находится в процессе внедрения, интересно взглянуть на эффект, который данная технология будет иметь для систем инспекции трафика и блокирования доступа. Современные системы используют SNI (а также, в продвинутых вариантах, TLS-сертификаты) для обнаружения имён узлов, с которыми пытается установить соединение пользователь. ESNI скрывает эти имена из SNI (TLS-сертификаты скрыты в новой версии TLS 1.3), причём, текущая версия ESNI использует для этого ключи, опубликованные в DNS.

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

Провайдер хостинга может использовать ключи, опубликованные под одним DNS-именем, для обеспечения доступа к “скрытым серверам” под совсем другими именами, это означает, что открытый запрос в DNS не будет раскрывать имя “целевого узла”. Например, Cloudflare сейчас использует одни и те же ключи для самых разных веб-узлов. Более того, “скрытый узел” может находиться за некоторым “фронтэндом”, имеющим другое, универсальное, имя – фактически, это Domain Fronting.

В идеале, для работы ESNI нужны DNSSEC (чтобы аутентифицировать источник ключей и защитить DNS-трафик от подмены) и DNS-over-TLS (чтобы защитить DNS-трафик от пассивного прослушивания). Но и в условиях незащищённой DNS, технология ESNI довольно эффективна (отмечу, что ESNI предусматривает и вариант, в котором ключи встраиваются в приложение, либо передаются каким-то ещё способом, без DNS).

В открытой DNS, системы анализа трафика, которые видят весь трафик клиента, могут сопоставить запрос в DNS для извлечения ключа ESNI и последующее TLS-соединение. DNS-ответ с ключами даже можно заблокировать, сделав использование ESNI невозможным (но только при условии, что ключи не были получены другим способом). Однако автоматическое корректное сопоставление имени из DNS-запроса и сессии TLS – представляют серьёзную дополнительную задачу, которая тем сложнее, чем больше объём трафика, анализируемого системой фильтрации. (Конечно, уже само наличие ESNI может являться признаком подозрительного соединения.)

То есть, ESNI, в случае массового внедрения, довольно заметно повлияет на ландшафт систем инспекции трафика. А кроме того, данная технология может подстегнуть рост распространённости DNSSEC и DNS-over-TLS. Впрочем, пока что ESNI не поддерживается распространёнными веб-серверами, да и соответствующий RFC не вышел из статуса черновика.

(Как работает ESNI – можно посмотреть на моём тестовом сервере TLS 1.3, там реализована поддержка.)



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

Внёс некоторые дополнения на сервер tls13.1d.pw. Во-первых, появилась поддержка “пересогласования” (renegotiation) параметров соединения. В TLS 1.3 есть отдельный механизм, который позволяет серверу запросить у клиента другие параметры протокола Диффи-Хеллмана, конечно, при условии, что клиент их поддерживает. Для этого сервер, в самом начале процесса установления соединения, отправляет сообщение HelloRetryRequest. (Технические подробности есть в описании TLS.) Я давно планировал дописать на сервер поддержку классического варианта протокола Диффи-Хеллмана (DH), который есть в Firefox. Так как по умолчанию браузеры используют эллиптический вариант, включение классического – как раз требует пересогласования параметров. То есть, чтобы заработал классический DH, нужно реализовать пересогласование.

Чуть ранее – я добавил поддержку ESNI. Так вот, в процессе отладки механизма пересогласования выяснилось, что в библиотеке NSS, которая используется Firefox, содержится ошибка в реализации механизма HelloRetryRequest, которая не позволяет использовать вместе с ним ESNI (про ошибку разработчикам я сообщил; вроде, планируют исправить). Так что теперь действие полезного механизма ESNI в Firefox можно наблюдать только в тех случаях, когда сервер не использует пересогласования: для этого нужно обновить страницу tls13.1d.pw несколько раз – группы DH на сервере выбираются псевдослучайным образом, так что, если выбор совпал с перечнем ключей браузера, присланных по умолчанию, то пересогласования не будет, а сработает ESNI.

Соответственно, во-вторых, – это и есть реализация классического DH. Его ещё называют “мультипликативным” вариантом, DH “в конечном поле” и так далее, а если говорить не слишком научно, то это алгоритм в арифметике остатков. Chrome/Chromium поддерживают только эллиптический вариант, соответственно, там увидеть классический никак не удастся. А вот в Firefox – можно. На сервере я реализовал только одну группу, зато самую “большую”: FFDHE3072. В предыдущих версиях TLS – сервер мог выбрать произвольную группу для классического DH, в версии TLS 1.3 список зафиксировали. Я некоторое время назад писал про то, как выбираются параметры для этих групп. По сравнению с эллиптическими вариантами, запись ключа FFDHE3072 – весьма длинная, 384 байта. Вот так результат выглядит на скриншоте:

FFDHE screen

В-третьих, добавил ограниченную поддержку TLS Cookies: она ограниченная потому, что соответствующее расширение передаётся сервером и принимается от клиента, но корректность его использования клиентом пока никак не проверяется. TLS Cookies – это инструмент, позволяющий серверу проверить, что клиент действительно отвечает и намеревается установить TLS-соединение. Особенно полезны, когда используется безсессионный транспорт, как в DTLS.

(Вообще, использование пересогласования может поломать какие-то другие библиотеки, поддерживающие TLS 1.3, но пока что я таких не обнаружил.)



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

При установлении TLS-соединения имя узла передаётся в открытом виде, внутри поля (или расширения) SNI – Server Name Indication. На стороне сервера имя узла требуется для того, чтобы выбрать правильный набор сертификатов и серверных ключей, в случае, если на одном IP-адресе отвечает несколько TLS-узлов.

С появлением новой версии TLS 1.3, в которой зашифрована существенная часть сообщений, передаваемых при установлении соединения, вновь обострились споры относительно того, что хорошо бы зашифровать и SNI – ведь через это поле происходит утечка информации о том, с каким именно узлом устанавливается соединение.

Предлагалось несколько вариантов защищённого SNI. Вероятно, будет выбран вариант, использующий ключи в DNS: для него уже есть поддержка в браузере Firefox (версии 64 и Nightly) и на веб-узлах Cloudflare, несмотря на то, что сама спецификация пока в состоянии черновика.

Защищённый вариант называется ESNI (Encrypted SNI) и доступен только для TLS 1.3 (и, в будущем, выше). Рассмотрим, как он работает.

Основная идея следующая. В DNS размещается специальная запись (сейчас это TXT-запись, но, возможно, скоро появится выделенный для ESNI тип), в которой публикуется открытый ключ сервера (для протокола Диффи-Хеллмана (DH), см. ниже) и другие криптографические параметры. А именно: шифронабор, используемый для защиты SNI; группа для DH; контрольная сумма; время действия ключа. Для адресации DNS-записи служит специальное имя, имеющее вид _esni.example.com (здесь важен символ подчёркивания в начале).

Например, для узла tls13.1d.pw имя записи будет таким: _esni.tls13.1d.pw. А значением является структура с криптографическими параметрами, закодированная в Base64. Вот действующее значение для _esni.tls13.1d.pw:

“/wGu7tnmACQAHQAgLukkHH6AiIAPYODmYK/6Nz3H7N58nYZyb/WG62h4TTgAAhMBAIAAAAAAXCPQTgAAAABcQ3ROAAA=”

Эти данные нужны клиенту для того, чтобы сгенерировать симметричный ключ, который он использует для зашифрования имени сервера в ESNI.

Обычно, клиентом является браузер. Он действует по следующему алгоритму: извлекает из DNS запись, содержащую данные ESNI; используя эти данные, генерирует свою часть обмена по протоколу Диффи-Хеллмана, вычисляет общий секрет, на его основе генерирует симметричный ключ и зашифровывает SNI симметричным шифром. Получившийся шифротекст – передаётся в составе нового расширения сообщения TLS ClientHello ESNI. Вместе с зашифрованным SNI передаётся клиентский ключ DH, который необходим серверу для получения симметричного ключа. Таким образом, третья сторона, прослушивающая канал, не может прочитать значение SNI.

Конкретный пример используемых криптосистем: для (эллиптического) DH используется кривая Curve25519; в качестве шифра – AES в режиме GCM. Все эти параметры, как указано выше, записаны в DNS.

Сервер обнаруживает наличие ESNI по присутствию соответствующего расширения в сообщении ClientHello, отправленном браузером (с этого сообщения начинается процесс установления TLS-соединения). Так как сервер знает секретный ключ DH, он может вычислить общий секрет и симметричный ключ, а после этого – расшифровать имя сервера, полученное в ESNI. Также сервер, успешно обработавший ESNI, отвечает с подтверждением: возвращает клиенту уникальное значение, полученное в зашифрованной части ESNI; при этом значение передаётся в защищённом виде, то есть, получаем ещё один, дополнительный, канал подтверждения подлинности сервера (для клиента).

Очевидно, что в данной схеме имя узла потенциально передаётся в открытом виде при запросе в DNS, поэтому необходимо использовать инструменты защиты DNS-трафика. В частности, в Firefox используют DNS-over-HTTPS (DoH), но данная технология защищает трафик только на “последней миле”, то есть, на пути от рекурсивного резолвера к клиенту. Кроме того, DoH никак не решает проблему подмены DNS-ответов. То есть, в полной мере ESNI заработает только при условии поддержки DNSSEC и внедрения TLS для защиты DNS-транзакций на всех этапах. Тем не менее, с чего-то нужно начать, поэтому внедрение ESNI в распространённый браузер – весьма хороший стимул, который может подтолкнуть и другие технологии.

В качестве теста, я реализовал ESNI, в только что описанной версии, на сервере tls13.1d.pw. Попробовать можно при помощи браузеров Firefox Nightly или Firefox 64. Поддержка ESNI включается в “about:config” (в 64-й версии уже должна быть включена “из коробки”); обязательно нужно также активировать DoH (DNS-over-HTTPS), указав URI сервера, который будет обслуживать DNS-запросы – в Firefox ESNI без DoH не работает.

Если вы зайдёте на tls13.1d.pw с поддержкой ESNI, то информацию об этом сервер выведет в начале страницы – как на скриншоте (update, 10/04/19: ошибку в Firefox исправили, начиная с версии 66.0.2 в основной линейке, так что поддержка ESNI теперь не зависит от пересогласования параметров;update, 05/02/19: из-за ошибки в библиотеке NSS, на которой базируется реализация TLS в Firefox, увидеть при помощи этого браузера ESNI на tls13.1d.pw можно только в том случае, если сервер не использовал пересогласование параметров – то есть, нужно несколько раз обновить страницу; подробнее – в отдельной записке).

Screenshot



Комментарии (1) »
Навигация по запискам: Раньше »