getClientRects() и getBoundingClientRect() раскрывают субпиксельные различия вёрстки, которые фингерпринтят устройство — без обращения к canvas.
У каждого элемента на странице есть позиция и размер, которые JavaScript может считать с точностью до доли пикселя. Попросите браузер вернуть точный прямоугольник, который занимает заголовок, и в ответ придут числа с плавающей точкой вроде 312.234375 — точность, которая человеческому глазу совершенно не нужна, но которая возникает из-за хинтинга шрифтов, субпиксельного сглаживания и платформо-специфичной раскладки текста. Эти числа немного различаются от устройства к устройству, и скрипт, измеряющий их в достаточном количестве, способен превратить обычную вёрстку страницы в сигнал слежки — без единого элемента canvas и без чтения хотя бы одного пикселя.
Ключевые выводы
getClientRects()иgetBoundingClientRect()возвращают значенияDOMRectс субпиксельной (дробной) точностью — точностью, которая меняется в зависимости от рендеринга шрифтов, масштабирования DPI и движка вёрстки текста в ОС.- Измерение прямоугольников отрисованного текста — это фингерпринтинг на основе вёрстки: не требует ни элемента
<canvas>, ни чтения пикселей, ни запроса разрешения, поэтому обходит защиты, нацеленные конкретно на canvas. - Он коррелирует с canvas-фингерпринтингом, но не идентичен ему: оба проистекают из различий в рендеринге шрифтов и графического конвейера; их сочетание даёт более высокую уверенность, чем каждый по отдельности.
- Antidetect-браузеры вроде GoLogin и Dolphin{anty} снабжены отдельными переключателями для спуфинга "Rects" — молчаливое признание индустрии antidetect-браузеров, что этот сигнал реально проверяется на практике.
- Проверка отпечатка BrowserInsight на странице fingerprint check показывает сигналы вёрстки и canvas, которые ваш браузер раскрывает прямо сейчас, бок о бок.
Что на самом деле возвращает getClientRects()
getClientRects() и её более простой аналог getBoundingClientRect() — обычные API вёрстки, стандартизированные в спецификации CSSOM View Module. Они существуют, чтобы JavaScript мог отвечать на повседневные вопросы вроде «виден ли этот элемент сейчас в области просмотра?» или «где именно заканчивается эта перенесённая строка текста?». Ничего в них не напоминает инструмент слежки.
Вызовите getBoundingClientRect() на любом элементе — и получите один DOMRect: top, left, width, height и производные от них границы, описывающие его ограничивающий прямоугольник относительно области просмотра. Вызовите вместо этого getClientRects() — и получите целый список прямоугольников, по одному на строчный блок (line box), что важно для строчного содержимого: предложение, переносящееся на три строки, вернёт три отдельных прямоугольника, каждый со своими координатами. Range.getClientRects() делает то же самое для произвольного текстового выделения, позволяя скрипту измерить конкретный фрагмент символов, а не весь элемент.
Возвращаемые значения — не целые числа. Это числа с плавающей точкой двойной точности, потому что движок вёрстки браузера позиционирует текст с использованием субпиксельной арифметики, хотя ваш экран в итоге округляет всё до физических пикселей. Именно эта лишняя точность — дробный остаток, который никогда не отрисовывается одинаково на разных устройствах, — и есть вся основа этого метода фингерпринтинга.
Почему числа различаются от устройства к устройству
Если два браузера отрисовывают одинаковый HTML с одинаковым CSS, почему прямоугольники вообще должны отличаться? Между «вот текст» и «вот его итоговые пиксели» лежит несколько слоёв, каждый из которых вносит небольшую, воспроизводимую вариацию:
- Хинтинг и шейпинг шрифтов. Движок формирования текста в ОС — DirectWrite в Windows, Core Text в macOS, FreeType/HarfBuzz в Linux — решает, как именно контуры глифов привязываются к пиксельной сетке. Разные правила хинтинга дают разную ширину продвижения (advance width) для одной и той же строки в одном и том же шрифте.
- Соотношение пикселей устройства. Дисплей HiDPI (
window.devicePixelRatioравно 2 или 3) округляет субпиксельную вёрстку до более мелкой физической сетки, чем дисплей 1x, сдвигая дробную часть каждой координаты. См. справку MDN поdevicePixelRatioо том, как браузер раскрывает эту информацию. - Доступность шрифтов и подстановка. Если запрошенный шрифт не установлен, браузер подставляет запасной шрифт с другими метриками — тот же механизм, на котором строится фингерпринтинг по шрифтам, только здесь сигналом служит сама геометрия прямоугольника, а не простой бит «присутствует/отсутствует».
- Движок и версия браузера. Chromium (Blink), Firefox (Gecko) и Safari (WebKit) реализуют собственную логику вёрстки текста и переноса строк, поэтому идентичная разметка может законно измеряться с разницей в несколько сотых пикселя между движками, а иногда и между версиями одного и того же движка.
- Уровень масштабирования и масштабирование текста в ОС. Масштаб страницы и масштабирование через настройки специальных возможностей ОС (Windows «сделать текст крупнее», масштабирование дисплея в macOS) — всё это проходит через тот же конвейер вёрстки и сдвигает субпиксельный остаток.
Ни одна из этих вещей не является настройкой, которую кто-то сознательно включает ради приватности. Это побочные эффекты обычного рендеринга — именно поэтому итоговые прямоугольники стабильны для конкретного устройства и сессии, но различаются от одного устройства к другому.
ClientRects-фингерпринтинг против canvas-фингерпринтинга
Эти две техники — близкие родственники: обе эксплуатируют различия конвейера рендеринга, коренящиеся в шрифтах, GPU и текстовых движках ОС, — но отличаются тем, к чему они обращаются и насколько легко их обнаружить.
| Свойство | ClientRects-фингерпринтинг | Canvas-фингерпринтинг |
|---|---|---|
| Поверхность API | Обычная вёрстка DOM (getClientRects, getBoundingClientRect) | <canvas> + 2D-контекст (toDataURL, getImageData) |
| Требует чтения пикселей | Нет | Да |
| Виден для блокировщиков, нацеленных на canvas | Нет | Да — расширения перехватывают именно эти вызовы |
| Источник сигнала | Субпиксельная геометрия вёрстки текста/элементов | Цвета растрированных пикселей |
| Типичная энтропия | Умеренная сама по себе; сильная в сочетании со шрифтами | Высокая сама по себе |
| Обнаруживается как «был прочитан offscreen-canvas» | Неприменимо — canvas вообще не задействован | Да, через мониторинг вызовов API |
Практическое следствие в том, что делает rects-фингерпринтинг привлекательным как для трекеров, так и для разработчиков antidetect-браузеров: любая защита, которая специально следит за вызовами canvas API — блокировщик-расширение, слой farbling, скрипт мониторинга вроде того, что описан в нашем гайде по canvas, — здесь ничего не перехватит, потому что canvas вообще не создаётся. Скрипту достаточно тихо измерить вёрстку обычного текста и заголовков, уже присутствующих на странице, чтобы получить сопоставимый сигнал.
Как на самом деле проводится измерение
Типичная реализация отрисовывает несколько стилизованных текстовых элементов — часто смешивая несколько шрифтов, размеров и CSS-свойств вроде letter-spacing, которые, как известно, вызывают расходящееся субпиксельное округление, — а затем считывает их прямоугольники:
// Иллюстративный набросок измерения на основе rects
function measureRects() {
const probe = document.createElement('div');
probe.style.cssText = 'position:absolute; visibility:hidden; font-size:14px; letter-spacing:0.3px;';
probe.style.fontFamily = 'Arial, sans-serif';
probe.textContent = 'BrowserInsight fingerprint probe 0123456789';
document.body.appendChild(probe);
const rects = probe.getClientRects();
const values = Array.from(rects).flatMap(r => [r.width, r.height, r.left, r.top]);
document.body.removeChild(probe);
return values; // передаётся в хеш вместе с другими сигналами
}
Элементу не обязательно быть видимым — visibility: hidden всё равно участвует в вёрстке, поэтому создаваемые им прямоугольники реальны. Обычно измеряется и хешируется сразу несколько тестовых строк, шрифтов и комбинаций CSS — тот же подход «измерить много маленьких сигналов и объединить их», что используется в фингерпринтинге в целом; о том, как такие сигналы складываются в общий идентификатор, читайте в нашем руководстве по фингерпринтингу браузера.
Где это встречается на практике
Эта техника не получает столько внимания прессы, сколько canvas или WebGL, но она хорошо известна в двух конкретных нишах экосистемы:
- Поставщики решений для фингерпринтинга и антифрода включают измерения на основе rects как один из многих входных сигналов именно потому, что он дёшев в вычислении и ортогонален защитам, на которых сосредоточено большинство инструментов приватности.
- Antidetect-браузеры — инструменты, созданные для того, чтобы каждый экземпляр браузера представлял иной, но последовательный профиль отпечатка, — относятся к этому серьёзно настолько, что предоставляют выделенные настройки. И GoLogin, и Dolphin{anty} снабжены переключателями специально для спуфинга или нормализации вывода "Rects", рядом с переключателями canvas и WebGL. Наличие специально созданного переключателя — разумный признак того, что «это действительно проверяется»: производители не создают инструменты спуфинга для сигналов, которые никто не читает.
Как снизить свою раскрываемость
В основных браузерах нет отдельного переключателя «отключить getClientRects», потому что этот API критически важен для обычной вёрстки — выделение текста, прокрутка к элементу, всплывающие подсказки и практически любой JavaScript-фреймворк для интерфейсов зависят от него. Доступные меры смягчения повторяют те, что работают против canvas-фингерпринтинга, поскольку у них общий корень:
- Отдавайте предпочтение единообразию, а не кастомизации. Tor Browser стандартизирует рендеринг шрифтов и снижает точность нескольких более тонких API вёрстки, сокращая круг пользователей, среди которых вас можно выделить, — та же философия, что применяется к canvas.
- Ограничьте установленные шрифты и расширения. Каждый дополнительный установленный шрифт — ещё один способ, которым подстановка запасного шрифта может сдвинуть размеры прямоугольника. Стандартный набор шрифтов на стандартной ОС сложнее выделить, чем сильно кастомизированный.
- Используйте защиты в духе resistFingerprinting.
privacy.resistFingerprintingв Firefox округляет и стандартизирует несколько значений, связанных с рендерингом, снижая субпиксельную дисперсию, на которую опирается эта техника, — так же, как он ограничивает вывод canvas и WebGL. - Проверьте, что вы раскрываете. Запустите проверку отпечатка BrowserInsight на странице fingerprint check, чтобы увидеть сигналы canvas, WebGL и другие сигналы рендеринга в одном месте, а затем сравните результат в обычном браузере и в браузере с усиленной приватностью, чтобы понять, какие настройки реально что-то меняют.
Как и с canvas, здесь работает парадокс антифингерпринтинга: редкий, самодельный спуфинг rects, который перестарался — возвращает подозрительно круглые числа или демонстрирует нулевую субпиксельную дисперсию в каждом тестовом замере, — может оказаться более заметным, чем исходный сигнал, который он должен был скрыть.
Часто задаваемые вопросы
ClientRects-фингерпринтинг — это то же самое, что canvas-фингерпринтинг?
Нет, хотя они тесно связаны. Canvas-фингерпринтинг считывает растрированные пиксели из offscreen <canvas>; ClientRects-фингерпринтинг считывает субпиксельную геометрию вёрстки обычных DOM-элементов или текста, вообще без участия canvas. Оба уходят корнями в различия рендеринга шрифтов и вёрстки текста платформы, поэтому обычно коррелируют, но защита, созданная только для canvas, никак не мешает этой технике.
Останавливает ли это блокировщик canvas?
Сам по себе — нет. Блокировщики canvas перехватывают API, специфичные для canvas, такие как toDataURL() и getImageData(). getClientRects() и getBoundingClientRect() — это несвязанные методы вёрстки DOM, поэтому у блокировщика, ограниченного canvas, нет причин их перехватывать.
Может ли эта техника идентифицировать меня сама по себе?
С высокой уверенностью — редко: многие устройства имеют похожие конвейеры рендеринга и дают сопоставимые прямоугольники. Трекерам она полезнее всего в сочетании со шрифтами, canvas, WebGL и другими пассивными атрибутами — так же, как каждый отдельный сигнал в полном отпечатке вносит лишь частичную энтропию, а не полную идентичность.
Почему antidetect-браузеры отдельно упоминают настройки "Rects"?
Потому что техника реальна и проверяется некоторыми поставщиками фингерпринтинга и антифрод-решений. Инструментам, созданным для представления последовательной поддельной идентичности, приходится нормализовать или рандомизировать этот сигнал так же, как они делают это для canvas и WebGL, — иначе сигнал rects раскрыл бы настоящее устройство даже через в остальном хорошо замаскированный профиль.
Заключение
ClientRects-фингерпринтинг напоминает, что «защита от фингерпринтинга» не может означать «заблокировать canvas — и дело сделано». Любой API, достаточно точный, чтобы отражать рендеринг шрифтов, масштабирование DPI или вёрстку текста платформы, достаточно точен и для фингерпринтинга — а обычные методы вёрстки DOM, на которые уже опирается любое веб-приложение, полностью этому соответствуют. Понимание механизма позволяет оценить, действительно ли конкретный инструмент приватности покрывает этот случай, а не просто предполагать, что защита canvas — это вся история целиком.
Рекомендуем почитать:


