Хабрахабр

Звуковой отпечаток компьютера через AudioContext API

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

Он не требует получения никаких разрешений пользователя.
Метод работает по умолчанию во всех браузерах, кроме Tor.

Недавно журналистка NY Times Кашмир Хилл обнаружила, что некая малоизвестная компания Sift накопила на неё досье объёмом 400 страниц. Там список покупок за несколько лет, все сообщения хостам на Airbnb, лог запусков кошелька Coinbase на мобильном телефоне, IP-адреса, заказы пиццы с iPhone и многое другое. Аналогичный сбор ведут несколько скоринговых фирм. Они учитывают до 16 000 факторов при составлении «рейтинга доверия» каждого пользователя. Трекеры Sift установлены на 34 000 сайтов и мобильных приложений.

Список установленных шрифтов, плагинов, разрешение экрана и другие параметры в сумме дают достаточно бит информации для получения уникального ID. Поскольку следящие куки и скрипты не всегда хорошо работают или отключены у клиента, трекинг пользователей дополняют фингерпринтингом — это набор методов для получения уникального «отпечатка» браузера/системы. Хорошо работает фингерпринтинг через canvas.

Веб-страница отправляет браузеру команду отрисовать графический объект из нескольких элементов.

<canvas class="canvas"></canvas>

const canvas = document.querySelector('.canvas');
const ctx = canvas.getContext('2d');
// Maximize performance effect by
// changing blending/composition effect
ctx.globalCompositeOperation = 'lighter'; // Render a blue rectangle
ctx.fillStyle = "rgb(0, 0, 255)";
ctx.fillRect(25,65,100,20); // Render a black text: "Hello, OpenGenus"
var txt = "Hello, OpenGenus";
ctx.font = "14px 'Arial'";
ctx.fillStyle = "rgb(0, 0, 0)";
ctx.fillText(txt, 25, 110); // Render arcs: red circle & green half-circle
ctx.fillStyle = 'rgb(0,255,0)';
ctx.beginPath();
ctx.arc(50, 50, 50, 0, Math.PI*3, true);
ctx.closePath();
ctx.fill();
ctx.fillStyle = 'rgb(255,0,0)';
ctx.beginPath();
ctx.arc(100, 50, 50, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();

Результат выглядит примерно так:

Функция Canvas API под названием toDataURL() возвращает URI с данными, которые соответствуют этому результату:

console.log(canvas.toDataURL());
/*
Ouputs something like: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNby
mblAAAWDElEQVQImWNgoBMAAABpAAFEI8ARexAAAElFTkSuQmCC"
*/

Этот URI отличается на разных системах. Затем он хэшируется и используется вместе с другими битами данных, которые составляют уникальный отпечаток системы. Среди прочего:

  • установленные шрифты (около 4,37 бита идентифицирующей информации);
  • установленные плагины в браузере (3,08 бита);
  • заголовки HTTP_ACCEPT (16,85 бита);
  • user-agent;
  • язык;
  • часовой пояс;
  • размера экрана;
  • камера и микрофон;
  • версия ОС;
  • и др.

Хэш отпечатка canvas добавляет ещё 4,76 бита идентифицирующей информации. Хэш отпечатка WebGL — 4,36 бита.

Тест фингерпринтинга

Недавно в дополнение к набору параметров добавился ещё один: звуковой отпечаток через AudioContext API.

Ещё в 2016 году этот метод идентификации уже использовали сотни сайтов, такие как Expedia, Hotels.com и др.

Алгоритм действий такой же: браузер выполняет задачу, а мы записываем результат выполнения и вычисляем уникальный хэш (отпечаток), только в данном случае данные извлекаются из аудиостека. Вместо Canvas API идёт обращение к AudioContext API, это интерфейс Web Audio API, который поддерживают все современные браузеры.

При этом никакой звук не записывается и не воспроизводится. Браузер генерирует низкочастотный аудиосигнал, который обрабатывается с учётом звуковых настроек и оборудования, установленного на устройстве. Колонки и микрофон не задействуются.

Преимущество этого метода фингерпринтинга в том, что он независим от браузера, так что позволяет отслеживать пользователя даже после перехода с Chrome в Firefox, затем в Opera и так далее.

Тест отпечатка через AudioContext API

Как получить отпечаток, пошаговое руководство:

  1. Во-первых, нужно создать массив для хранения значений частоты.

    let freq_data = [];

  2. Затем создаётся объект AudioContext и различные узлы для генерации сигнала и сбора информации, используя встроенные методы объекта AudioContext.

    // Create nodes
    const ctx = new AudioContext(); // AudioContext Object
    const oscillator = ctx.createOscillator(); // OscillatorNode
    const analyser = ctx.createAnalyser(); // AnalyserNode
    const gain = ctx.createGain(); // GainNode
    const scriptProcessor = ctx.createScriptProcessor(4096, 1, 1); // ScriptProcessorNode

  3. Отключаем громкость и соединяем узлы друг с другом.

    // Disable volume
    gain.gain.value = 0;
    // Connect oscillator output (OscillatorNode) to analyser input
    oscillator.connect(analyser);
    // Connect analyser output (AnalyserNode) to scriptProcessor input
    analyser.connect(scriptProcessor);
    // Connect scriptProcessor output (ScriptProcessorNode) to gain input
    scriptProcessor.connect(gain);
    // Connect gain output (GainNode) to AudioContext destination
    gain.connect(ctx.destination);

  4. Используя ScriptProcessorNode, создаём функцию, которая собирает частотные данные во время обработки звука.
    • Функция создаёт типизированный массив Float32Array с длиной, равной числу (частоте) значений данных в AnalyserNode, а затем заполняет его значениями.
    • Эти значения затем копируются в массив, который мы создали ранее (freq_data), чтобы мы могли легко записывать их в выходные данные.
    • Отключаем узлы и выводим результат.

      scriptProcessor.onaudioprocess = function(bins) {
      // The number of (frequency) data values
      bins = new Float32Array(analyser.frequencyBinCount);
      // Fill the Float32Array array of these based on values
      analyser.getFloatFrequencyData(bins);
      // Copy frequency data to 'freq_data' array
      for (var i = 0; i < bins.length; i = i + 1) {
      freq_data.push(bins[i]);
      }
      // Disconnect the nodes from each other
      analyser.disconnect();
      scriptProcessor.disconnect();
      gain.disconnect();
      // Log output of frequency data
      console.log(freq_data);
      };

  5. Начинаем воспроизводить тон, так что звук генерируется и обрабатывается в соответствии с функцией.

    // Start playing tone
    oscillator.start(0);

Результат получается примерно такой:

/*
Output:
[
-119.79788967947266, -119.29875891113281, -118.90072674835938,
-118.08164726269531, -117.02244567871094, -115.73435120521094,
-114.24555969238281, -112.56678771972656, -110.70404089034375,
-108.64968109130886, ...
]
*/

Эта комбинация значений хэшируется для создания отпечатка, который затем используется с другими битами идентификации.

Для защиты от такого трекинга можно использовать расширения вроде AudioContext Fingerprint Defender, которые подмешивают случайный шум в отпечаток.

NY Times приводит адреса email, по которым можно обратиться в трекинговые фирмы и попросить показать собранную на вас информацию.

  • Zeta Global: онлайн-форма
  • Retail Equation: returnactivityreport@theretailequation.com
  • Riskified: privacy@riskified.com
  • Kustomer: privacy@kustomer.com
  • Sift: privacy@sift.com, онлайн-форма деактивирована после публикации статьи


СПЕЦИАЛЬНЫЕ УСЛОВИЯ на PKI-решения для малого и среднего бизнеса до 30.11.2019 г. по промо-коду AL003HRFR. Предложение действует для новых клиентов. Подробности уточняйте у менеджеров +7 (499) 678 2210, sales-ru@globalsign.com.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть