Добавил поддержку TLS 1.3 (это самая свежая версия протокола) на сервере, где работает dxdt.ru. Сейчас на сервере доступны только TLS 1.3 и TLS 1.2 (все более ранние – я отключил). Так как поддержка актуальной версии TLS требует подходящей версии Apache (собранного с веткой OpenSSL 1.1.1), то пришлось перейти с операционной системы CentOS 7 на Fedora 30, где все нужные сборки есть “из коробки” (вариант собрать “в сторонке” и OpenSSL, и Apache, и mod_ssl из исходников – как-то не очень, даже с учётом того, что мне это приходится проделывать в рамках других проектов). А в CentOS, к сожалению, непонятно когда появится TLS 1.3, данная ОС постепенно становится малопригодной для использования.
Тем не менее, вроде бы ничего особенно не сломалось, а сайт работает.
Комментировать »
Под “спутниковыми интернетами” здесь подразумевается предоставление глобального “широкополосного” доступа к Интернету спутниковой группировкой. Таких систем предлагается несколько, а сами аппараты уже начали запускать: например, Starlink и OneWeb. Я уже писал, что подобная спутниковая система является отличной платформой для создания универсального орбитального радара, предназначенного для наблюдения за поверхностью Земли. В этот раз речь о другом: насколько легко будет обнаруживать наземные станции, используемые для доступа к данному спутниковому каналу связи?
Понятно, что наземный терминал должен излучать сигнал, который непосредственно может принимать спутник (варианты с доставкой одного “плеча” по традиционным наземным каналам – конечно, возможны, но это не то, чего ожидаешь от беспроводной “технологии будущего”). А раз терминал излучает, то его работу можно обнаружить при помощи пассивного приёмника. (Здесь необходима оговорка про направленные антенны: у антенн существуют боковые лепестки диаграммы направленности, они есть даже у узконаправленных антенн, а вопрос только в коэффициенте усиления утекающего сигнала; да, в теории, можно минимизировать боковые утечки, но такая антенна вряд ли подойдёт для спутникового терминала.)
Высокочастотные сигналы (то есть, сигналы с малой длиной волны), используемые для создания цифрового канала связи, обычно имеют и хорошо узнаваемую сигнатуру, и встроенные метки времени (требуются для синхронизации). Это означает, что несколько приёмников, имеющих точное общее время и находящихся на некотором расстоянии, смогут вычислять положение спутниковых терминалов в режиме реального времени с высокой точностью и тут же “наносить точки на карту”.
Разместить приёмники, предназначенные для мониторинга радиоэфира, можно на вышках сотовой связи – они давно служат платформой для решения сходных задач: здесь есть куда поставить антенны, есть источники времени, есть каналы передачи данных и гарантированное питание. Соответствующее оборудование могут устанавливать те же “интеграторы”, которые разворачивают системы сотовой связи. Покрытие вышками в российских городах хорошее.
В теории, сигнал, используемый для организации спутникового канала, может быть замаскирован (например, если у наземного терминала и спутниковой группировки есть общие секретные ключи, то возможна реализация довольно “скрытного” кодирования). Однако, во-первых, резко упадёт пропускная способность, так что ни о каком “широкополосном” доступе речи уже идти не может; во-вторых – некоторый сигнал всё равно остаётся и его можно обнаружить, используя в качестве опорных сигналы специально закупленных терминалов и сигналы спутников. А главное, что о маскировке сигнала терминалов речи, конечно, не идет. Так что с обнаружением и геолокацией источников – проблем не возникнет.
Комментировать »
(Записка с перечнем поддерживаемых элементов протокола TLS 1.3. Чтобы не потерялось.)
Тестовый сервер TLS 1.3 на tls13.1d.pw:
1. Версия протокола: 1.3 (0x0304), Draft-28 (совпадает с 1.3, кроме номера версии) и Draft-23 (в этой версии есть небольшие отличия в алгоритмах от 1.3, версия до сих пор встречается на практике). Вообще, draft-версии соответствуют черновикам RFC, протокол реализовывался (в статусе экспериментального) параллельно с разработкой RFC. Например, Draft-23 был очень распространён: его поддерживали и Firefox, и Chrome. Когда я запускал тестовый сервер, RFC ещё не было, и именно версия Draft-23 была основной.
2. Криптосистема подписи: сейчас используется ECDSA в группе P-384; раньше был вариант в группе P-256 (это названия кривых), можно сделать оба варианта (попеременно выбирать для каждого запроса), но тогда нужна обработка второго сертификата – возможно, добавлю. А вот поддержку RSA пока решил не добавлять.
3. Поддержка DH (при согласовании общего секрета в рамках установления соединения): P-256, P-384, x25519, а также “классический” FFDH с разрядностью 3072 бита (поддерживается, например, Firefox).
4. Шифры: AES-128-GCM-SHA256, AES-256-GCM-SHA384, ChaCha20Poly1305. Нет CCM-режимов. Update 12/01/20: добавлено динамическое изменение приоритетов шифров на стороне сервера; добавлена поддержка сообщений KeyUpdate и, соответственно, ротация симметричных сессионных ключей.
5. Поддержка HelloRetryRequest: сервер, с некоторой вероятностью, отвечает на ClientHello сообщением пересогласования параметров – HelloRetryRequest (HRR), запрашивая другую группу из поддерживаемых клиентом; это происходит только в том случае, если набор групп, заявленный клиентом, позволяет. Это довольно богатое для целей исследования реализаций TLS направление, потому что здесь, в том или ином виде, требуется сохранение состояния соединения. Пример: предположим, что клиент заявляет для DH поддержку x25519, P-256 и FFDHE-3072, но ключ передаёт только для x25519 (это обычная ситуация в TLS 1.3); в таком случае сервер может ответить HelloRetryRequest, запросив либо P-256, либо FFDHE-3072.
6. Поддержка TLS cookie: при ответе с HelloRetryRequest – сервер передаёт клиенту TLS cookie. Это специальное расширение ClientHello/HelloRetryRequest, в котором передаётся некоторое значение – клиент должен вернуть это же значение в новом запросе ClientHello; у TLS cookie две основных роли: 1) “выгрузить” клиенту представление состояния начинающейся сессии, чтобы сервер не хранил дополнительные записи на своей стороне; 2) проверить, что клиент действительно активен и отвечает на запросы по адресу, с которого получено сообщение ClientHello. (Тестовый сервер совпадение значений TLS cookie не проверяет.)
7. Поддержка ESNI: поддерживается два варианта криптосистем DH – P-384, x25519 (в ESNI используется протокол Диффи-Хеллмана со статическими ключами, которые публикуются в DNS); шифр для ESNI – один: AES-128-GCM.
Комментарии (7) »
Некоторое время назад тестовый сервер TLS 1.3, который я реализовал и, в меру сил, поддерживаю по адресу tls13.1d.pw, продемонстрировал свою практическую полезность. А я забыл об этом написать на dxdt.ru – соответственно, пишу сейчас.
Тестовый сервер поддерживает сочетание HelloRetryRequest (HRR) и ESNI (зашифрованное поле SNI). То есть, сервер иногда отправляет клиенту запрос на пересогласование параметров и при этом обрабатывает ESNI. HRR+ESNI – весьма редкое сочетание, на обычном сервере скорее не встречается (но может быть имитировано в рамках активной атаки), это и позволило мне обнаружить в NSS (библиотека, используемая браузером Firefox) ошибку, которая до этого успешно прошла через релиз-тесты.
Ошибка состояла в следующем: использование ESNI должно скрывать имя сервера, но в NSS соединение с HRR+ESNI обрабатывалось некорректно, соответственно, во втором ClientHello, в ответ на запрос HRR, имя сервера передавалось в открытом виде (в обычном расширении SNI). В итоге – утекало имя сервера, а на tls13.1d.pw в некоторых случаях не удавалось отобразить сведения про ESNI для пользователей Firefox (причина в том, что во втором ClientHello, из которого только и имеет смысл брать сведения о соединении, ESNI просто не было). Об ошибке я сообщил в Mozilla, ошибка (Bug 1517714) исправлена в релизе NSS_3.43, вышедшем в марте. Сейчас исправленный релиз уже разошёлся по всем основным сборкам браузера Firefox.
Комментировать »
Существенная часть информации о 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).
Несмотря на существенные сложности, хорошо скрытые протоколы можно разработать, а также и реализовать. Но они настолько отличаются от используемых сейчас, например, в распространённых мессенджерах, что быстрого внедрения ожидать не приходится.
Комментарии (1) »
Подробное описание того, как работает (на практике) технология 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) »
Пара статей, которые вышли некоторое время назад.
В “Открытых системах” опубликована моя статья про фильтрацию и блокировки в Интернете. В основном, с точки зрения использования метаинформации для обеспечения избирательности фильтров, применительно к DNS и Вебу (здесь рассматривается HTTPS), но и про возможное развитие в разрезе маршрутизации трафика тоже немного порассуждал, в разделе “Перспективы и фантастика”.
Ссылка: “За час до закрытия Интернета“.
На ресурсе D-Russia.ru – моя статья о зависимостях веб-сайтов от “внешних” библиотек. Речь про различные jQuery и т.п., которые загружаются с централизованных сервисов, являющихся внешними относительно сайта-источника. Такие зависимости очень распространены, но про них забывают (и пользователи, и администраторы веб-сайтов).
Ссылка: “Централизованный Интернет“.
Комментировать »
По адресу 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) – всё работает нормально, как ожидается.
(Это временный сервис, точнее – демонстратор технологии.)
Update (25/07/2019): эксперимент закончен, сервис пока недоступен.
Комментарии (4) »