
Перекрёстный допрос: разоблачение маскировки отпечатка с помощью JavaScript-инъекций
21 ДЕКАБРЯ 2021 | БРАУЗЕРНЫЕ ОТПЕЧАТКИ
Ищете способы скрыть свой онлайн-отпечаток? Возможно, вы сталкивались с использованием JavaScript-инъекций. Этот метод относительно простой и дешёвый. Но безопасен ли он? Наше исследование показало, что ответ прост — нет. Мы рассмотрели уязвимости этого метода и то, как его можно обнаружить. А ещё, в статье есть код, который вы сможете протестировать самостоятельно.
Что такое маскировка через JS-инъекцию?
Вот три основных метода маскировки браузерного отпечатка:
JavaScript-инъекция
Нативный подход
Сочетание вышеупомянутых методов
Что мы подразумеваем под отпечатком?
Современные системы могут точно определить, кто мы такие, используя информацию, которую мы оставляем о себе в интернете. Они создают отпечаток, который идентифицирует нас как уникального пользователя. Используя функциональные возможности браузера, такие как API, они узнают информацию о самом браузере, операционной системе и языках, которые мы используем. Когда системы обнаружения находят несоответствия или недостающую информацию, это становится проблемой.
Давайте кратко рассмотрим нативный подход к маскировке отпечатков. Он использует новые исполняемые файлы, которые базируются на браузерах с открытым исходным кодом, таких как Chromium. Этот метод заменяет определённые значения вашего отпечатка, чтобы скрыть вашу личность. Нативный подход получил своё название благодаря тому, что он очень надёжен и сложен для обнаружения. Это наиболее эффективный метод, однако его реализация требует больше времени и ресурсов.
JavaScript-инъекция — это способ вставки кода на веб-страницу для изменения значений определённых атрибутов. Например, подобно адвокату, который представляет подозреваемого на допросе, JS-инъекция может перезаписать атрибуты, чтобы скрыть настоящую личность пользователя. Как Сол из «Лучше звоните Солу», который отвечает на вопросы полиции от имени своего клиента, JS-инъекция может имитировать поведение другого пользователя.
JavaScript-инъекция позволяет скрыть настоящие атрибуты браузера, заменив их на другие значения.
Возможно, это самый популярный метод, так как он дёшев и прост в использовании, но его недостатком является то, что его легко обнаружить — об этом мы расскажем далее.
Как осуществляется JS-инъекция?
Существует несколько методов маскировки JS-инъекции. Некоторые выбирают фреймворки автоматизации браузеров, такие как Selenium и Puppeteer. Есть и те, кто предпочитает расширения браузера, поскольку это, вероятно, самый удобный вариант. Наше исследование также выявило, что для этих целей можно использовать бесплатный HTTPS-прокси mitmproxy, хотя мы не нашли примеров его использования на практике.

Как работает JS-инъекция через браузерные расширения?
Как мы объяснили более подробно в нашей предыдущей статье, с помощью расширений можно добавить новые функции браузеру. Они состоят из нескольких элементов, как показано на диаграмме ниже:
Файл, описывающий расширение: manifest.json
Файлы контентных скриптов
Ядро, состоящее из фоновых скриптов
Тестирование JS-инъекции на практике

Представляем наше расширение
Перейдём к самому интересному! Мы рады представить наше собственное браузерное расширение, которое мы будем использовать в качестве примера. Давайте познакомимся: Saul — Better JS Injection Call, инновационное решение для скрытия отпечатков.
Для тех, кто интересуется кодом, первым делом мы представляем сердце нашего расширения — файл manifest.json. Он определяет все его возможности.
1{2 "manifest_version": 2,3 "name": "Better JS Injection Call - Saul - A artistic solution for fingerprint masking",4 "version": "1.0.0",5 "content_scripts": [6 {7 "matches": [""],8 "js": ["bettercall.js"],9 "run_at": "document_end",10 "all_frames": true,11 "match_about_blank": true12 }13 ]14}15
Теперь давайте рассмотрим контентный скрипт нашего расширения — bettercall.js. Нам просто нужно добавить наш код JavaScript для маскировки отпечатков браузера. В блоке content_script нашего файла manifest выше (с пятой строки и далее) вы видите некоторые инструкции, которые похожи на бессмыслицу. По сути, они означают, что наш контентный скрипт будет добавлен ко всем веб-страницам и фреймам (то есть на HTML-элементы, загружающие другие веб-страницы или HTML-страницы внутри веб-страницы, которую мы посещаем).
Перейдём к бизнес-логике нашего расширения. Представляем наш bettercall.js:
1const maskLanguage = (language) => {2 Object.defineProperty(navigator, 'language', {3 get: () => language,4 });5};67const doMask = (method, ...args) => {8 const stringifiedMethod = method instanceof Function9 ? method.toString()10 : `() => { ${method} }`;1112 const stringifiedArgs = JSON.stringify(args);1314 const scriptContent = `15 (${stringifiedMethod})(...${stringifiedArgs});16 document.currentScript.parentElement17 .removeChild(document.currentScript);18 `;1920 const scriptElement = document.createElement('script');21 scriptElement.textContent = scriptContent;22 document.documentElement.append(scriptElement);2324 const scriptElement2 = document.createElement('script');25 scriptElement2.textContent = "document.body.innerHTML += 'Injected';";26 document.documentElement.append(scriptElement2);2728};2930doMask(maskLanguage, 'eo-Multilogin');
Наше расширение изменяет атрибут navigator.language с языка, который мы установили, на eo-Multilogin. EO — это символ языка эсперанто, созданного для облегчения глобального общения.
Этот код добавляет строку «Injected» в тело всех контекстов, в которые он внедряется. Мы будем использовать её для оценки работы нашего расширения.
Применение на практике
Давайте включим наше расширение из меню chrome://extension и посмотрим, что произошло с нашим navigator.language.

Давайте продолжим наш пример с допросом полиции и представим, что фреймы, которые загружает главная страница, это допросные комнаты в полицейском участке. В идеале мы ожидаем, что наш адвокат будет с нами на протяжении всего допроса — так же, как мы ожидаем полной инъекции...
1<html>2<head>3</head>4<body>5<br>http://www.iframetest.test/iframe.html<br>6<iframe width="100" height="55" id="normalFrame" src="http://www.iframetest.test/iframe.html"></iframe><br>7<br>about:blank<br>8<iframe width="100" height="55" id="aboutBlankFrame" src="about:blank"></iframe><br>9<br>data://<br>10<iframe width="100" height="55" id="dataFrame" src="data:text/html,<html><body></body></html>"></iframe><br>11<br>javascript:<br>12<iframe width="100" height="55" id="jsFrame" src='javascript:const a=0;'></iframe><br>13<br>sandbox<br>14<iframe width="100" height="55" id="sandboxFrame" sandbox src="http://www.iframetest.test/iframe.html"></iframe><br>15<br>srcdoc<br>16<iframe width="100" height="55" id="srcdocFrame" srcdoc="<html><head></head><body></body></html>"></iframe><br>17</body>18</html>
Ниже мы видим результаты.
Наш флаг «Injected» показывает, что большинство страниц содержат инъекцию. Однако фреймы, использующие URL-адреса data:// и javascript:// — нет. К сожалению, наш адвокат Сол очень занят и не всегда с нами. Поэтому в допросных комнатах для data:// и javascript:// наш браузер будет отвечать на некоторые вопросы о себе без покровительства своего адвоката. Давайте посмотрим, как это будет работать...
Перекрёстный допрос одним кликом
Мы все знакомы с методикой перекрёстного допроса, где задаются одни и те же вопросы одним и тем же людям снова и снова, но в разном порядке. Такая тактика может вывести из себя многих людей и довести их до признания вины.
В аналогичной ситуации оказался и наш бедный браузер без своего защитника. Код JavaScript начинает перекрёстный допрос, задавая те же вопросы как нашей веб-странице, так и её подстранице, которая загружается через элемент iframe.
Ниже показана страница, содержащая iframe javascript://.
1<html/>2<iframe id="jsFrame" src="javascript:console.log('hello');"/></iframe/>3</body/>
Мы можем доказать, что подозреваемый лжёт. Наш контентный скрипт, который был разработан для внедрения JavaScript и маскировки браузерного отпечатка, нельзя внедрить в фреймы с URL-адресами data:// и javascript://. Следовательно, результат должен был быть одинаковым, но не является таковым.

Пришло время для ваших экспериментов
Что ещё может вызвать вышеупомянутую проблему?
Хотите попробовать решить её самостоятельно?
Cross-Examination: новый код для выявления маскировки браузерных отпечатков с помощью JS.
Протестируйте его сейчас — нажмите на ссылку и перейдите к HTML PoC.
Наш код собирает информацию о вашем браузере как из основного окна, так и из iframe: User-Agent, отпечаток Canvas и аудио, публичный IP-адрес WebRTC, разрешение экрана и часовой пояс.
Затем он генерирует хеш из собранной информации и использует его в качестве идентификатора посетителя для обоих окон. Наш код затем сравнивает идентификаторы, полученные из основного окна и iframe. В случае отличий он сообщает об аномалии.
Обратите внимание: мы используем javascript:// iframe, а не data:// iframe. Наши эксперименты показывают, что некоторые фреймворки для автоматизации браузера успешно внедряются в data:// iframe, но не в javascript:// iframe.
JS-инъекции в популярных расширениях
Помимо коммерческих решений, использующих JS-инъекции для маскировки отпечатков цифрового устройства, магазин Google Chrome предлагает сотни расширений, обещающих скрыть/подделать некоторые атрибуты браузера через JS-инъекции, такие как Canvas хеш, User-Agent и другие.
Мы исследовали некоторые из самых распространённых решений и выявили, что они могут быть обнаружены с помощью нашего метода. Некоторые расширения используют ещё более сомнительные подходы, такие как отсутствие внедрения JS-кода даже в обычные фреймы.
Мы проанализировали их, изучив раздел content_script в файле manifest.json, и пришли к следующим выводам:

Заключение: использование JS-инъекций несёт значительные риски
Вот единственный вывод, который мы можем сделать из наших экспериментов: использование JS-инъекций для маскировки браузерных отпечатков несёт в себе большие риски для любого бизнеса, который управляет множеством аккаунтов.
Этот подход широко используется из-за своей простоты и доступности, но его легко обнаружить, как показывают наши эксперименты. Даже гибридное решение не уменьшает этот риск: хотя одна его часть может быть более защищённой, часть, использующая маскировку с помощью JS-инъекций, так же легко обнаруживается.
Вот почему Multilogin использует собственные нативные решения: браузер Mimic, основанный на Chromium, и StealthFox, основанный на Mozilla Firefox. Надёжный способ избежать рисков — выбирать решения, которые не используют JS-инъекции. Ведь зачем рисковать, если можно выбрать более безопасный путь?