Canvas fingerprinting за межами основ: чому два ідентичні Chrome рендерять різні пікселі
Два пристрої з однаковими Chrome, OS та GPU все одно рендерять різні canvas-пікселі. Чому конвеєр рендерингу недетермінований, чому privacy-шум дає зворотний ефект і де canvas у сучасному detection-стеку.
Canvas fingerprinting використовується у продакшені з 2012 року. Ідея проста: попросити браузер відрендерити 2D-контент, зчитати пікселі назад і захешувати їх. Різні пристрої видають дещо різні пікселі для тих самих інструкцій, і ці відмінності достатньо стабільні, щоб ідентифікувати пристрій між сесіями.
Це загальновідомо. Менш зрозуміло інше — чому техніка працює, чому ідентичні конфігурації ПЗ на ідентичному залізі все одно дають різний вивід. Відповідь лежить на перетині драйверів GPU, рендерингу шрифтів та арифметики з плаваючою комою.
Конвеєр рендерингу не детермінований
Коли JavaScript викликає context.fillText("Cwm fjord bank glyphs vext quiz", 4, 45), Chrome не рендерить пікселі сам. Він генерує інструкції для Skia — 2D-графічної бібліотеки, — яка, своєю чергою, видає команди малювання GPU-прискореному бекенду (зазвичай ANGLE на Windows, Metal на macOS або програмний fallback у контейнерах).
На кожному кроці накопичуються невеликі відмінності реалізацій:
-
Підсистема шрифтів Skia обирає сімейство шрифтів. Якщо Arial не встановлено, вона підбирає fallback — і цей fallback залежить від встановлених у системі шрифтів.
-
Обраний шрифт рендериться у запитаному розмірі через FreeType (на Linux), DirectWrite (на Windows) або Core Text (на macOS). Кожна бібліотека має різні алгоритми хінтингу.
-
Застосовується субпіксельне позиціонування. Саме тут ідентичні шрифти починають давати різні пікселі — алгоритм округлює позиції до дробових піксельних зсувів, а правила округлення відрізняються між платформами.
-
Растеризований текст композитується на canvas. Змішування роблять GPU-шейдери на системах з апаратним прискоренням і CPU-код у режимі fallback.
Кожен крок може вносити відмінності в одне-два піксельних значення. Окремо непомітні. Разом — унікальні.
Версії драйверів GPU домінують у fingerprint
Дві машини з Windows 11 і чипами Intel UHD Graphics 620 можуть давати різний вивід canvas, якщо їхні драйвери GPU відрізняються. Intel випускає оновлення драйверів кілька разів на рік, і кожне оновлення може змінювати субпіксельну фільтрацію, гамма-корекцію та згладжування тексту.
Це означає, що стабільність canvas fingerprint обмежена частотою оновлень драйверів. Користувач, який оновлює графічний драйвер — часто мовчки, через Windows Update, — побачить, що його canvas fingerprint змінився.
Detection-системи справляються з цим, трактуючи canvas fingerprint як один із багатьох сигналів, а не як самостійний ідентифікатор. Коли він змінюється, але інші сигнали залишаються стабільними (TLS fingerprint, WebGL renderer, часовий пояс, встановлені шрифти), відвідувача все одно розпізнають.
Рендеринг emoji — золота жила
Найбільш ідентифікувальний елемент canvas fingerprint — це часто не текст чи фігури, а emoji. Рендеринг emoji залежить від emoji-шрифту, який постачається з OS: Segoe UI Emoji на Windows, Apple Color Emoji на macOS, Noto Color Emoji на Android.
Навіть у межах однієї OS рендеринг emoji змінюється між версіями. Веселка на Windows 10 рендериться інакше, ніж на Windows 11. Усміхнене обличчя в iOS 16 має інше згладжування, ніж в iOS 17.
Сучасні скрипти canvas fingerprinting спеціально рендерять послідовності emoji, включно з новими доповненнями до Unicode. Відвідувач, який стверджує, що працює на iPhone Safari, але не може відрендерити emoji, додане в iOS 17, працює на старішій iOS — або бреше про платформу.
Фреймворки автоматизації дають характерні fingerprint
Headless Chrome, що працює в Docker-контейнері без GPU, використовує SwiftShader для рендерингу. SwiftShader дає вивід canvas, який внутрішньо узгоджений, але відрізняється від будь-якого Chrome з апаратним прискоренням.
Сигнатура впізнавана: незвично чисте згладжування, специфічні значення кольору в областях градієнта та краї тексту, що не збігаються з жодним відомим драйвером GPU. Canvas fingerprint, який збігається зі SwiftShader у Chrome 124 в Linux-контейнері, майже напевно є автоматизацією — жоден реальний користувач не запускає браузер у такий спосіб.
Puppeteer-extra-stealth намагається підробити вивід canvas, перехоплюючи toDataURL() і повертаючи змінені дані. Але модифікація часто вносить власні артефакти — патерни шуму, що повторюються між сесіями, які парадоксально роблять зусилля з анти-fingerprinting помітнішими, ніж якби нічого не робилося.
Чому ін'єкція шуму погано працює
Орієнтовані на приватність браузери на кшталт Brave впорскують шум у вивід canvas, щоб завадити відстеженню. Ідея — додати невеликі випадкові варіації піксельних значень, щоб той самий пристрій давав різні fingerprint щосесії.
На практиці ін'єкція шуму має три проблеми:
1. Сам шум є fingerprint. Відвідувач, чий вивід canvas змінюється при кожному завантаженні, але інші сигнали залишаються ідентичними, розпізнається як браузер, що впорскує шум. Це саме по собі ідентифікує.
2. Алгоритм шуму стабільний. Реалізація Brave дає специфічні патерни шуму, що не відповідають природній варіативності рендерингу GPU. Detection-системи можуть відрізнити вивід canvas, що виглядає зашумленим, від того, що виглядає природним.
3. Складні системи комбінують зразки. Кілька рендерів на одній сторінці або між сесіями можна усереднити. Якщо шум малий, середнє сходиться до базового детермінованого fingerprint.
Що фіксує canvas fingerprinting
Крім очевидного візуального виводу, canvas fingerprinting може як побічний ефект витягти кілька атрибутів пристрою:
Час рендерингу — тривалість рендерингу canvas розкриває можливості GPU. 4K-десктоп із дискретним GPU рендерить швидше, ніж середньокласний ноутбук.
Метрики тексту — measureText() повертає точні піксельні ширини, що варіюються залежно від рендерингу шрифтів. Ширину тексту можна використати як fingerprint навіть без рендерингу.
Підтримка композитних операцій — деякі браузери або конфігурації GPU підтримують розширені композитні режими. Перевірка підтримки розкриває межі можливостей.
Ефекти фільтрів — фільтри у стилі CSS, застосовані до canvas, дають різний вивід на різних GPU, особливо фільтри розмиття та тіні (drop-shadow).
Де canvas fingerprinting вписується в detection-стек
Сам по собі canvas fingerprinting не є надійним ідентифікатором. Драйвери змінюються. Користувачі перемикають браузери. Ін'єкція шуму поширена серед аудиторії, орієнтованої на приватність.
Його справжня сила — у ролі перехресної перевірки. Коли сесія стверджує, що це користувач, який повернувся, на основі cookie або входу в акаунт, canvas fingerprint виступає другим сигналом: збіг з історичним fingerprint підтверджує заяву, розбіжність сигналізує про захоплення акаунта чи угон сесії.
Для bot detection canvas fingerprinting чудово ловить контейнеризовану автоматизацію. У реальних користувачів є реальні GPU. Реальні GPU дають упізнавані сигнатури рендерингу. Усе, що рендериться як SwiftShader або як погано підроблений canvas, потрапляє в кошик майже напевно бот.
Техніка 2012 року й досі працює у 2026-му з тієї самої причини: рендеринг детермінований для кожного середовища, але його практично неможливо повністю підробити. Кожна спроба сховатися залишає сліди самої спроби.