Daily MaverickBOOK EXCERPT: Kitchens of the Karoo – how cooks of old mastered stone, sourdough and coffeeESPNTakeaways as Rays even series against GuardiansLa NaciónActualizaciones de las encuestas en Florida y quién gana las elecciones 2026 con DeSantis de salidaPunchTinubu transmits NDLEA, NSIB amendment bills to SenateThe Jerusalem Post'We're going to hit them hard': Trump threatens Iran as Tehran escalates shipping attacksESPN DeportesRays arma rally tras error e iguala serie a Guardians한겨레한판에 4만3천원, 브라질산 달걀 ‘고가 수입’ 질타에…농식품공사 “수입 다변화 차원”InquirerQCPD relieves police clearance chief amid probe into service disruptionSCMP ChinaChina’s Dune-like sand crawler could turn the whole Taklamakan Desert into an iron mineSouth China Morning PostNo rush to T+1: Hong Kong exchange won’t hurry settlement-time change, sources sayהידעןעתיד הבינה המלאכותית: ״החלק המסובך זה אנחנו, זה בני אדם״Digital Spy5 Coronation Street spoilers for tonight reveal Bethany baby twist aftermath
The Daily Newsstand · Free, Always
Wednesday, October 14, 2026

AudioContext и шрифты: на кого точно не подумаешь если профиль забанят

Translate

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

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

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

Привет! Я Александр, пишу для антидетект-браузера Aurorium и по совместительству являюсь специалистом в вопросах автоматизации и парсинга. В этом материале я хочу подробно изучить такой элемент в экосистеме антидетекта, как AudioContext и шрифты, разобрать на что они могут влиять и как проверяются. Постараюсь сильно не душнить в своих попытках объяснить материал, но и вы тоже меня поймите, все же не про термитов читаете, местами может быть душновато. По традиции сварите чашечку кофе или чая и соорудите пару бутербродов — мы начинаем! 

Когда вы работаете с антидетект-браузером (любым антидетектом, не обязательно с Aurorium) и у вас банят профиль, на что в первую очередь вы будете грешить и куда копать? Скорее всего на прокси, потом уже на сам антидетект-браузер, и я уверен, в самую последнюю очередь (а может и вовсе никогда не подумаете об этом) вы решите, что причина в аудио-отпечатке или лишних шрифтах. 

И это нормально, долгое время вообще считалось, что наиболее важными составляющими отпечатка браузера (кстати, если совсем не понимаете о чем речь, рекомендую прочитать сперва статью — «Отпечатки браузера: что это такое и как работает») являются Canvas и WebGL. Если на шрифты хоть как-то обращали внимание, то на аудио смотрели примерно как на дождевых червей — они есть, пусть занимаются там как-нибудь сами, главное чтоб нас не касались.

Но слишком очевидные вещи стали чересчур очевидными, когда из каждого утюга звучит как мантра — Canvas важен, WebGL важен, все сосредоточились на них, и антифрод понял: подмена этих понятий уже не является чем-то выдающимся. И начал уделять больше внимания пассивным браузерным интерфейсам. К ним и относят Web Audio API и системные шрифты.

Web Audio API — звук без динамиков

Графику, например, мы можем увидеть, как и антифрод. Когда системы защиты просят устройство отрисовать какой-то элемент для проверки консистентности, пользователь ничего не видит, отрисовка происходит бесшумно. Но аудио… Это же звук, а звук всегда ассоциируется с динамиками, он должен где-то прозвучать, чтобы его можно было распознать и сравнить. Но это не так работает.

Аудио-отпечаток не требует доступа к микрофону. Сбор сигнатуры основан на синтезе звука внутри изолированного контекста OfflineAudioContext, который рассчитывает аудио-граф в оперативной памяти на максимальной скорости центрального процессора без вывода данных на динамики.

То есть пользователь, как и в случае с проверкой графики, ничего не услышит и не узнает, а антифрод увидит, сравнит и сделает вывод.

Вот как это происходит:

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

Роль DynamicsCompressorNode

Итак, после того, как звук будет извлечен, чтобы заставить железо проявить индивидуальность, его прогоняют через компрессор (DynamicsCompressorNode).

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

Но так как под капотом у этого инструмента крутятся сложные нелинейные формулы, компрессор можно настроить под задачи антифрода:

comp.threshold.setValueAtTime(-50, ctx.currentTime); // Порог срабатывания 
comp.knee.setValueAtTime(40, ctx.currentTime); // Плавность сжатия 
comp.ratio.setValueAtTime(12, ctx.currentTime); // Степень сжатия (агрессивная)
comp.attack.setValueAtTime(0, ctx.currentTime); // Мгновенная атака 
comp.release.setValueAtTime(0.25, ctx.currentTime); // Время восстановления 

Откуда уникальность?

И вот мы подходим к самому интересному: откуда берется уникальность, если волна примерно одинаковая, да и алгоритм сжатия (когда мы прогоняем полученный программный звук через компрессор) не сильно может похвастаться уникальностью. Разница возникает на уровне «железа», которое выполняет вычисления:

  1. Разные процессоры по-разному округляют дроби. Чипы Intel, AMD и Apple Silicon считают числа с плавающей запятой через разные наборы инструкций. В 12–16 знаках после запятой будут отличия, небольшие, в 2-3 числах, но они будут.

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

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

Выше пример работы скрипта, который сперва просит процессор сгенерить программный звук (этап 1), и на этом этапе видно, что волна получилась максимально предсказуемой. Далее (этап 2) звук прогоняется через компрессор и суммирует полученные результаты. И вот эта сумма и нужна антифроду для анализа.

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

Уточнение — качественный антифрод имеет свою базу данных устройств и их отпечатков, и он может сопоставить полученный хеш с данными из своей базы. Когда он (антифрод) видит, что устройство позиционирует себя как Windows на базе процессора Intel, а полученный аудиоотпечаток совпадает с отпечатком устройства на процессоре AMD, у системы защиты закономерно возникнут вопросы.

Примерно так и строится проверка Аудио-хеша любого вашего устройства. 

Шрифтовой фингерпринтинг

Со шрифтами ситуация более понятная, но не менее интересная. Небольшое введение в контекст: у каждой операционной системы есть свой уникальный набор шрифтов, которые характерны только для нее, и когда они встречаются на другой ОС это считается ненормальным поведением. И казалось бы, что сложного — просто надо получить список всех шрифтов, лежащих на устройстве пользователя. 

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

Интерфейс CanvasRenderingContext2D и метод measureText() позволяют получить такой список косвенным путем и достаточно точно, скажу я вам.

Как это работает, на примере Fallback

Принцип основан на поведении CSS Font Stack. Когда скрипт запрашивает отрисовку текста несуществующим шрифтом, браузер применяет резервный шрифт, указанный в конце цепочки.

Работает это так — в качестве резервного шрифта используется шрифт, присутствующий на любом устройстве в любой  операционной системе monospace. Антифрод замеряет ширину строки, если написать этим шрифтом примерно такой вот текст — mmmmmmmmmmlliW@19#$. Полученное значение учитывается как эталонное. 

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

Как вы понимаете, перебрать 200-300 шрифтов за 10-30 миллисекунд для антифрода вообще не проблема.

Ну и соответственно, когда антифрод находит среди шрифтов Windows шрифты, которые могут быть только на Mac, или наоборот, будут вопросы.

Почему такая странная строка? Почему не написать обычный текст? Нужна смесь из максимально узких и максимально широких букв и спецсимволов. В моноширинном шрифте они все насильно вытянуты под одну фиксированную сетку. Но в любом нормальном шрифте пропорции этих букв уникальны. Это и гарантирует, что ширина строки с реальным шрифтом никогда случайно не совпадет с monospace.

Платформенный рассинхрон

Есть еще одна особенность, которая позволяет антифроду вычислять подмены более качественно. 

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

Это позволяет детектить такую ситуацию, когда на Linux принудительно ставят пакет шрифтов Windows, но антифрод сможет распознать несоответствие шрифта операционной системе. Для примера я провел быстрый замер этих параметров для шрифта Times New Roman на Windows и на Linux, и получил отличные значения для разных операционных систем. Результат на скриншоте ниже.

Чем это может быть чревато? Тем, что, если в User-Agent указан Windows, а антифрод решит, что имеет дело с Linux, он посчитает это рассинхроном и пометит сессию, как подозрительную.

Как не нужно делать

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

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

Все, что антифроду нужно, это запустить параллельно два замера и сравнить результат. Если он отличается, сессия будет помечена, как подозрительная.

Кроме этого есть еще две распространенные ошибки маскировки:

  • Полное отключение API. Иногда в расширениях просто блокируют работу Canvas или AudioContext (возвращая null или ошибку). Но это аномальное поведение, так как у большинства обычных пользователей браузерные API по умолчанию включены и работают. Браузер, в котором звук «вырезан» привлечет к себе больше внимания защиты, чем обычный рабочий отпечаток.

  • «Пустой звук». Если запустить автоматизацию на «голом» сервере без эмуляции дисплея и звуковой карты, браузер тоже себя выдаст, он покажет 0 доступных аудиоканалов (maxChannelCount: 0) или нестандартную частоту звука.

Скрипт для проверки собственного окружения

Вы можете проверить свое окружение самостоятельно через DevTools браузера скриптом ниже.

await (async function auditBrowserConsistency() {
  // 1. Аудио-граф
  const renderAudio = async () => {
    const ctx = new OfflineAudioContext(1, 5000, 44100);
    const osc = ctx.createOscillator();
    const comp = ctx.createDynamicsCompressor();

    osc.type = 'triangle';
    osc.frequency.setValueAtTime(10000, ctx.currentTime);

    comp.threshold.setValueAtTime(-50, ctx.currentTime);
    comp.knee.setValueAtTime(40, ctx.currentTime);
    comp.ratio.setValueAtTime(12, ctx.currentTime);
    comp.attack.setValueAtTime(0, ctx.currentTime);
    comp.release.setValueAtTime(0.25, ctx.currentTime);

    osc.connect(comp);
    comp.connect(ctx.destination);
    osc.start(0);

    const buffer = await ctx.startRendering();
    const data = buffer.getChannelData(0).slice(4500, 5000);
    let sum = 0;
    for (let i = 0; i < data.length; i++) {
      sum += Math.abs(data[i]);
    }
    return sum.toFixed(7);
  };

  const [audio1, audio2] = await Promise.all([renderAudio(), renderAudio()]);
  const audioNoiseDetected = audio1 !== audio2;

  // 2. Шрифтовой стек
  const canvas = document.createElement('canvas');
  const ctx2d = canvas.getContext('2d');
  const testString = 'mmmmmmmmmmlliW@19#$';

  ctx2d.font = '72px monospace';
  const baseWidth = ctx2d.measureText(testString).width;

  const fontMarkers = {
    'Segoe UI (Windows)': '72px "Segoe UI", monospace',
    'Calibri (Windows)': '72px "Calibri", monospace',
    'Liberation Sans (Linux)': '72px "Liberation Sans", monospace',
    'Apple System (macOS)': '72px "-apple-system", monospace'
  };

  const detectedFonts = {};
  for (const [name, fontDecl] of Object.entries(fontMarkers)) {
    ctx2d.font = fontDecl;
    detectedFonts[name] = ctx2d.measureText(testString).width !== baseWidth;
  }

  // 3. Сверка с User-Agent
  const ua = navigator.userAgent;
  const claimsWindows = ua.includes('Windows');
  const claimsLinux = ua.includes('Linux') && !ua.includes('Android');

  let platformMismatch = false;
  if (claimsWindows && (!detectedFonts['Segoe UI (Windows)'] || detectedFonts['Liberation Sans (Linux)'])) {
    platformMismatch = true;
  }
  if (claimsLinux && detectedFonts['Segoe UI (Windows)']) {
    platformMismatch = true;
  }

  // Возвращаем итоговый отчет объектом
  return {
    audio: {
      run1: audio1,
      run2: audio2,
      noiseDetected: audioNoiseDetected,
      status: audioNoiseDetected ? 'FAIL (Обнаружен шум)' : 'PASS (Детерминирован)'
    },
    fonts: detectedFonts,
    platform: {
      claimedUA: ua,
      mismatchDetected: platformMismatch,
      status: platformMismatch ? 'FAIL (Шрифты противоречат ОС)' : 'PASS (Согласовано)'
    }
  };
})();

При помощи этого скрипта можно проверить свои профили на консистентность аудиоотпечатка и наличие подозрительных шрифтов. 

Для примера я выполнил несколько замеров на своем устройстве в антидетект-браузере Aurorium (создал два профиля, один с реальным аудио-отпечатком, а второй с добавлением шумов) и скрипт показал, что во всех замерах отпечаток детерминирован и не меняется при каждом новом обращении. Более того, система не просто брала аудио-отпечаток моего реального устройства (я сравнил отпечаток родного Chrome и отпечаток профиля, который не шумит и результаты были разные, в то время, как на другом антидетект-браузере цифра совпала).

Есть ли риски подобного совпадения? Чисто в теории банить за один конкретный элемент цифрового профиля никто не будет. Допустим, у вас 10-15 профилей на одном устройстве и все они имеют одинаковый аудиоотпечаток. Это выглядит подозрительно, особенно если заходить на один и тот же ресурс. Вероятнее всего антифрод снизит траст таких аккаунтов и появится риск связывания их в единую сетку. 

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

Заключение

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

Второе заблуждение — недооценивать влияние пассивных отпечатков на общий цифровой профиль устройства. Они уже давно перешли из статуса рудимента в статус полноценного элемента. И чем дальше, тем важнее становятся казалось бы, второстепенные элементы экосистемы антидетекта.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.