В предыдущей статье мы кратко рассмотрели фреймворк Snoopy. А также прошлись по существующим проблемам и ограничениям массового фингерпринтинга. Как обсуждалось ранее, текущая реализация фреймворка использует только одну функцию — последовательность размеров зашифрованных ресурсов. Поэтому далее опишем функциональные модули Snoopy в контексте именно этой функции. Входными данными для этого модуля являются IP, функция шифрования EF и функция снятия отпечатков F. Вывод модуля профилирования включает следующую информацию: 1) структура сайта, представленная графом G = (W, E), где W = {w1, w2, ..., wn} — набор из n различных страниц на сайте, а E = {(wi, wj) — множество направленных ребер, составляющих прямой маршрут из wi к wj}; 2) карта ресурсов RM: W → R, которая показывает взаимосвязь между страницами W и ресурсами R, где R = {r1, r2, ..., rm} — набор ресурсов, из которых состоит целевой сайт; 3) набор последовательностей загрузки ресурсов для всех n страниц, обозначаемых S = {S1, S2, ..., Sn}, где Si — последовательность ресурсов, запрашиваемых клиентом при доступе пользователя к странице wi; 4) сигнатуры ресурсов, т. е. зашифрованный размер каждого ресурса; 5) другие релевантные метаданные сайта, такие как возможность кэширования и информация о cookie. Опишем работу модуля профилирования с использованием алгоритма. Процедура GET_WEBSITE на первом шаге алгоритма использует методы автоматизированного обхода сайта и анализа страниц для построения графа G. Вершина U в G имеет направленное ребро к другой вершине V, если U представляет страницу со встроенными гиперссылками, помогающими пользователям переходить прямо на страницу V.  После этого процедурой GET_RESOURCES на втором шаге анализируем каждую страницу в W для извлечения последовательности загрузки ресурсов и компиляции карты ресурсов R. Полученный таким образом набор последовательностей загрузки ресурсов обозначается S, а уникальный набор встроенных ресурсов — R.  Процедура MAP_RESOURCES на третьем шаге создает биграф RM, вершины которого состоят из элементов W и R. Страница wi отображается ресурсами rj, когда rj встроен в wi, и это отображение обозначается ребром между вершинами, соответствующими wi и rj. На рис. 1 показан пример R, W, RM и G для сайта.   Для создания отпечатков Snoopy требуется набор данных, содержащий образцы трафика, демонстрирующие, как различные ресурсы проявляют себя в зашифрованном канале связи в различных контекстах просмотра. Процедура COLLECT_SAMPLES на шаге 4 алгоритма создает такой набор данных. Входными данными для этого шага являются набор страниц W и функция фингерпринтинга F, т. е. последовательность размеров зашифрованных ресурсов. Значения этой функции различаются в зависимости от контекста просмотра.   1. Факторы, не вызывающие изменений. Значения размеров зашифрованных ресурсов остаются неизменными при изменении таких факторов, как состояние сети. Snoopy не требует выборки трафика для учета таких факторов, которые не влияют на значения характеристик. 2. Факторы, вызывающие предсказуемые изменения. Различия в размерах зашифрованных ресурсов, обусловленных влиянием операционной системы, браузера и количеством используемых параллельных вкладок, носят детерминированный характер. Различия в значениях функций из-за этих факторов могут быть оценены Snoopy на основе знания предметной области сетевых и браузерных протоколов, включенных в его структуру. Следовательно, нет необходимости собирать дополнительные выборки трафика для учета таких контекстов просмотра. 3. Факторы, вызывающие различия в значениях характеристик сайтов. Snoopy требует выборок трафика для оценки значений функций из-за различий в факторах, зависящих от дизайна сайта — ресурсы, которые могут быть кэшированы, и информация, содержащаяся в cookie. Чтобы справиться с этим, процедура COLLECT_SAMPLES собирает образцы трафика с каждой страницы один раз с включенным кэшированием и разрешенными cookie и один раз с выключенным кэшированием и запрещенными cookie. Чтобы собрать образцы трафика для оценки значений характеристик, процедура COLLECT_SAMPLES создает несколько фиктивных клиентов для доступа к страницам по одной за раз в отдельных сеансах. Во время доступа к каждой странице зашифрованный трафик каждого клиента фиксируется инструментом мониторинга сети с начала до конца сеанса просмотра. Затем фреймворк обрабатывает каждую трассировку и разбивает ее на несколько подтрасс, соответствующих каждому ресурсу ri. Обратите внимание, что пакеты с одним и тем же ресурсом можно легко идентифицировать по зашифрованной трассировке, поскольку они имеют одинаковый номер подтверждения TCP. Фактический ресурс, который передается пакетами в подтрассировке, определяется путем расшифровки подтрассы с помощью ключей безопасности транспортного уровня (TLS), используемых фиктивными клиентами. Подтрассы и ресурсы, которым они соответствуют, хранятся в выборке с именем TSamples, где каждая запись имеет вид {подтрасса, r}. После того как собрана выборка TSamples, могут быть извлечены значения характеристик ресурсов для построения их сигнатур. На шаге 5 алгоритма процедура BUILD_SIGNATURES извлекает значение F каждого ресурса из соответствующей подтрассы, что, по сути, фиксирует эффект функции шифрования EF. Например, если подтрассировка содержит два пакета размером 50 байт каждый, значение F соответствующего ресурса будет равно 100 байтам. Для каждой извлеченной подтрассы в TSamples в базу данных сигнатур в featureDB делается запись вида <ri, sigi>, где sigi — F-значение ресурса ri. Во время прогнозирования потребуется обратное отображение наблюдаемого значения (fi) в соответствующий ресурс (ri), то есть EF1. Построение обратной функции шифрования EF1 является сложной задачей, поскольку невозможно выполнить однозначное сопоставление между параметрами зашифрованных и открытых ресурсов. Это связано с тем, что параметры зашифрованных ресурсов различаются в зависимости от контекста просмотра пользователем. Более того, из-за требования к соблюдению конечной модели запросов Snoopy не может собирать образцы трафика для всех возможных контекстов просмотра. Процедура CONSTRUCT_DICTIONARY строит реверсивную базу данных reverseFeatureDB из featureDB с учетом множественного сопоставления размеров зашифрованных и открытых ресурсов. Каждая запись reverseFeatureDB имеет форму < fi, Li >, где fi соответствует уникальному значению FS, а Li — список ресурсов с такими значениями. Li может включать несколько ресурсов с одинаковой подписью и несколько экземпляров одного и того же ресурса. На рис. 2 показан экземпляр featureDB и reverseFeatureDB, созданный из TSamples, собранного с соответствующего сайта. Во время прогнозирования для сужения списка возможных ресурсов и оценки их размеров в конкретном контексте Snoopy использует метаданные. Хотя кэшируемость и UA легко определить, cookie требуют сбора дополнительных образцов трафика. Процедура COMPUTE_COOKIE_VAR (шаг 7 алгоритма 1) обрабатывает образцы трафика для извлечения и сохранения метаданных, относящихся к cookie. 1. Чтобы учесть влияние трекинговых cookie на размер зашифрованного ресурса ri, моделируется параметр ct(ri). Во время профилирования отсутствует отслеживающий cookie, поскольку доступ к каждой веб-странице осуществляется в рамках отдельного сеанса. Возможный разброс значений характеристик, возникающий из-за встроенных трекинговых cookie в трассировку, может рассчитываться анализом исходного кода ресурса. Для каждого ресурса, содержащего отслеживающий cookie, процедура COMPUTE_COOKIE_VAR сначала определяет набор URL, с которых пользователь может перейти к ресурсу. Впоследствии для каждого из этих URL она сначала вычисляет размер ресурса с трекинговым cookie, когда он не зашифрован. Чтобы вычислить соответствующий размер зашифрованного ресурса, используется линейная интерполяция известных пар открытых и зашифрованных данных. Наконец, для каждого ресурса ri расчетный вариант сохраняется как: ct(ri) = {<URL1, ct(ri, 1)>, <URL2, ct(ri, 2)>, …, <URLx, ct(ri, x)>}.   Здесь ct(ri, j)(1 ≤ j ≤ x) обозначает увеличение размера зашифрованного ресурса ri из-за встроенного трекингового cookie, содержащего строку URLj.   2. Сессионные cookie. Параметр cs(ri) учитывает расхождение в размере зашифрованного ресурса ri из-за возможного отсутствия временных cookie при трассировке. Значение cs(ri) можно оценить, рассмотрев все данные, содержащиеся в поле заголовка, и их возможные значения. Большая часть этой информации имеет фиксированную длину, за исключением поля UA. Подобно трекинговым cookie, COMPUTE_COOKIE_VAR хранит эту информацию для каждого ресурса ri: cs(ri) = {<bo1, cs(ri, 1)>, <bo2, cs(ri, 2)>, …, <box, cs(ri, x)>}. Где cs(ri, j)(1 ≤ j ≤ x) обозначает увеличение размера зашифрованного ресурса ri из-за сессионного cookie, а boj переменная идентификатора браузера и ОС. Оцененные таким образом варианты, сохраняются в таблице поиска cookie_var, где каждая запись имеет вид <ri, {ct(ri), cs(ri)} >. Для ресурсов, которые не содержат трекинговые cookie, ct(ri) содержит значение NULL. Модуль прогнозирования Snoopy принимает в качестве входных параметров зашифрованную трассировку трафика T, и прогнозирует страницы, к которым осуществляется доступ в T, используя информацию, хранящуюся в базе данных. Фреймворк выполняет это предсказание в два этапа. Сначала он предсказывает ресурсы, присутствующие в T (predicted_resources). Затем эта последовательность используется для прогнозирования конечного набора веб-страниц (predicted_webpages), передаваемого пользователю фреймворка.   Для расчета прогнозируемых ресурсов в T Snoopy сначала разбивает входную трассу T на подтрассы, каждой из которых соответствует зашифрованный ресурс. Из каждой подтрассы значения признаков извлекаются и сохраняются в том порядке, в котором они появляются в T, в массив FValues. В качестве следующего шага фреймворк должен идентифицировать фактический ресурс, который может соответствовать каждому значению функции в FValues, в порядке их появления в T, путем поиска каждого из значений FValues[i] в словаре reverseFeatureDB. Пример: Рассмотрим два зашифрованных ресурса er1 и er2, извлеченных из T таким образом, что пользователь получает доступ к er1 раньше, чем к er2. Пусть f1 и f2 будут значениями из FValues er1 и er2 соответственно. Модуль прогнозирования обрабатывает f1, а потом f2. Предполагаем, что модуль правильно предсказал ресурс r4, соответствующий er1 после обработки f1. Опишем, как модуль обрабатывает f2. На рис. 3 показана гистограмма с накоплением, где на оси абсцисс показаны размеры зашифрованных ресурсов, а на оси ординат — частота появления различных ресурсов на сайте (например, r7 и r6 имеют одинаковый размер, но r7 встречается чаще, чем r6). Шаг 1: Расширение пространства поиска. Значение f2 может соответствовать или не соответствовать подписи ресурса в базе данных. Например, шаг 0 на рис.3 показывает сценарий, в котором f2 не соответствует ни одному из размеров зашифрованных ресурсов из reverseFeatureDB. Это происходит из-за различий в значении функции, вызванных возможным исключением сессионных и включением трекинговых cookie. Если f2 включает трекинговые cookie, его необходимо уменьшить (на ct(ri, j)) перед поиском в reverseFeatureDB. Аналогичным образом, если f2 не содержит сессионных cookie, перед поиском его необходимо увеличить (на cs(ri, k)). Однако определить наличие или отсутствие как сессионных, так и трекинговых cookie невозможно, поскольку неизвестно, где и что ранее делал пользователь. То есть и ct(ri, j), и cs(ri, k) не могут быть определены наверняка, поскольку идентификатор ресурса — i, ранее посещенный URL — j и строка пользовательского агента — k, неизвестны. Вместо этого нужно взять максимально возможные значения ct(ri, j) и cs(ri, k), полученные из cookie_var. Поэтому фреймворк ищет все значения в диапазоне [(f2 - max(ct)), (f2 + max(cs))] и добавляет все извлеченные ресурсы в relevant_resources. На первом шаге показано, что, хотя f2 наиболее близок к размерам r4, r5, r6 и r7, он также может принадлежать r2 или r3. Эти ресурсы образуют мультисет relevant_resources = {r2, r3, r3, r4, r5, r5, r6, r7, r7} и обозначены затонированной областью на рисунке. Шаг 2: Проверка достижимости. В обычной ситуации пользователь почти всегда начинает просмотр с определенной страницы и перемещается по ссылкам, встроенным в начальную и последующие страницы. Используем это предсказуемое поведение, чтобы улучшить прогнозирование. По сути, на основе информации о ресурсах, к которым ранее осуществлялся доступ, из совокупности Т удаляются ресурсы, недоступные с ранее посещенных страниц. Чтобы проверить доступность, используется структура сайта G и карта ресурсов RM. В отличие от аналогов, Snoopy учитывает просмотр нескольких вкладок, т. е. пользователь может перейти на страницу, которая напрямую доступна из любой вкладки, открытой в браузере в данный момент времени. Таким образом, фреймворк удаляет только те ресурсы, которые недоступны ни с одной из ранее посещенных страниц во всей совокупности T. Исключение недоступных ресурсов еще больше сужает поиск фактического ресурса, к которому осуществлялся доступ, тем самым уменьшая вычислительные затраты на более поздних этапах. Для примера er1 (= r4) — это ранее посещенный ресурс, который однозначно связан со страницей w3 (см. рис.1). Основываясь на этом факте, можно сделать вывод, что ресурс er2 может быть посещен из w3, либо из w4, либо из w5, но не из w1 или w2. Если какой-либо ресурс в наборе relevant_resources связан с w1 (у нас нет r1 в этом примере) или w2 (т. е. r2 и r3), его частота должна быть уменьшена соответствующим образом. Таким образом, набор доступных ресурсов теперь содержит {r3, r4, r5, r5, r6, r7, r7}, обозначенный с помощью reachable_resources, областью затонированной на рис.3 на шаге 2, которая уменьшена по сравнению с той же на шаге 1. Шаг 3: Учет изменений доступных ресурсов, индуцированных cookies. На этом шаге фреймворк вычисляет (sigi – ct(ri, x) + cs(ri, y)) для оценки фактического значения зашифрованной функции для каждого ресурса ri в reachable_resources с учетом предварительного доступа к ресурсу r4. Для этого он, как было описано выше, оценивает URL, содержащийся в трекинговом cookie, если значение ct(ri) не равно NULL. Этот URL (скажем, URLx), можно оценить с помощью метода, используемого для проверки достижимости. Также оценивается информация о браузере и ОС (скажем, boy), содержащаяся в сессионном cookie в заголовке прикладного уровня. Зная об URLx и boy, Snoopy извлекает соответствующие значения ct(ri, x) и cs(ri, y) из таблицы cookie_var. Этот шаг еще больше сужает область поиска. Данный процесс проиллюстрирован на шаге 3 на рисунке 5, где показан случай, когда ресурс r6 исключается из набора reachable_resources. В этом примере r4, r5 и r7 не изменились. Шаг 4: Присвоение веса ресурсам. На этом шаге фреймворк определяет ресурс, который с наибольшей вероятностью соответствует er2. Для этого присваивается вес каждому ресурсу в reachable_resources на основе количества экземпляров каждого ресурса в наборе и различий между их обновленными значениями характеристик и f2. Для каждого уникального ресурса ri∈reachable_resources обозначается расстояние между обновленным значением признака (из шага 3) и fi как diffi, а частоту ri в reachable_resources как freqi. Весовой коэффициент wi, присвоенный ресурсу ri, равен freqidiffi, где diffi≠ 0. Наконец, фреймворк считает, что ресурс с наибольшим весом соответствует ресурсу er2. Для прогнозирования посещаемых страниц Snoopy задействует алгоритм извлечения из последовательности predicted_resources, начиная с первого ресурса (скажем, rp1), и использует RM для идентификации всех страниц, содержащих rp1. Затем, используя набор последовательностей S, идентифицирует все страницы, где rp1 является первым ресурсом. Для каждой из этих страниц проверяется, чья последовательность загрузки ресурсов образует подпоследовательность predicted_resources. Когда страница идентифицирована, она добавляется в набор predicted_webpages. В случае если можно извлечь несколько последовательностей загрузки ресурсов из predicted_resources, выбирается тот, элементы которого кажутся ближе друг к другу по сравнению с другими. Как только последовательность извлечена, фреймворк удаляет их из predicted_resources и продолжает описанный выше процесс, начиная с нового первого ресурса в последовательности. Это продолжается до тех пор, пока последовательность predicted_resources не опустеет. В конце экстракции Snoopy исключает из рассмотрения уже извлеченные и кэшируемые ресурсы. Функциональные модули Snoopy реализованы на Python (с помощью библиотек Python с открытым исходным кодом). Трассировки шифрованного сетевого трафика, используемые для фингерпринта и тестирования, были перехвачены с помощью инструмента захвата пакетов TShark, работающего на сетевом шлюзе, хотя то же самое можно сделать на любом промежуточном сетевом маршрутизаторе.   – Факторы обобщения (GF, Generalization factors): набор факторов, связанных с поведением пользователя, которые метод стремится обобщить. GF ⊆ {I, BC, T, O, B, N}, где: I – интерес пользователя (набор страниц на сайте, который необходимо снять), BC – набор конфигураций браузера (настройки кэша и cookie), T – количество вкладок, используемых пользователем, O – набор обобщаемых операционных систем, B – набор браузеров,  N – сетевые условия. – Количество запросов (Nq, Number of Queries): максимальное количество запросов к сайту, которое злоумышленник может выполнить на целевом сайте для сбора образцов трафика для обучения (профилирование веб-страницы). – Точность фингерпринта (FA, Fingerprinting Accuracy): процент страниц, к которым пользователь обращался в сеансе и которые были правильно идентифицированы. В большинстве проведенных экспериментов фреймворк показал впечатляющие результаты прогнозирования с точностью ≥ 90% при оценке на большинстве сайтов в различных контекстах просмотра, при этом требовалось всего от 3 до 10 образцов трафика на страницу. В связке с методами ML точность выросла до ≥ 97% при соблюдении конечной модели запросов. Однако количество выборок трафика, требуемых компонентом ML, увеличилось при охвате большого количества контекстов просмотра. В этом топике мы подробно разобрали логику работы фреймворка Snoopy. Направлением будущих исследований авторы считают разработку еще более тесного дуэта фреймворка с методами ML при условии соблюдения ограниченного числа запросов для предотвращения автоматической блокировки работы фреймворка средствами защиты. И опять же, спешу напомнить, что основной задачей было лишь освещение того факта, что средства отслеживания действий пользователей в сети активно развиваются, а если учесть плотность таких средств в реале, можно себе много чего напридумывать. Тот, кто предупрежден, вооружен. «На каждой площадке со стены глядело всё то же лицо. Портрет был выполнен так, что, куда бы ты ни стал, глаза тебя не отпускали». НЛО прилетело и оставило здесь промокод для читателей нашего блога: — 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.