Верстакфорум практиков
рекламаiprazon: приватные серверные адреса IPv4 и SOCKS5, безлимитный трафик, бесплатный тест до 2 часов
ФорумБраузеры и профили

Canvas и WebGL: зачем их вообще трогают

byteflow
byteflow
Новичок
сообщений 225
с фев, второй сезон
22 декабря, 17:47первое сообщение

Читаю про отпечатки вторую неделю и никак не пойму, зачем трогают canvas. Картинка же везде одинаковая, что там уникального.

Объясните на пальцах, желательно с примером, что именно расходится у двух машин.

nullbyte
nullbyte
Ветеран
сообщений 2680
с апр
1 мая, 08:04#2

Одинаковая картинка выходит только на одинаковом железе и одинаковом наборе библиотек. Дальше начинаются мелочи.

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

WebGL болтливее вдвое. Кроме хеша отрисованной сцены оттуда достают строки:

const gl = document.createElement('canvas').getContext('webgl');
const d = gl.getExtension('WEBGL_debug_renderer_info');
console.log(gl.getParameter(d.UNMASKED_VENDOR_WEBGL));
console.log(gl.getParameter(d.UNMASKED_RENDERER_WEBGL));
console.log(gl.getSupportedExtensions().length);

Вендор и рендерер приходят почти открытым текстом, вроде ANGLE (NVIDIA GeForce GTX 1060 Direct3D11 vs_5_0 ps_5_0). Это точнее любого канваса.

если не воспроизводится, значит не понял
byteflow
byteflow
Новичок
сообщений 225
с фев, второй сезон
8 октября, 11:21#3
nullbyte: это точнее любого канваса

То есть строки рендерера важнее самого хеша?

gremlin_dv
gremlin_dv
Знаток
сообщений 1840
с мар
15 марта, 14:38#4

Важнее их согласованность. Если вендор говорит NVIDIA, а список расширений собран под встроенную графику Intel, набор рассыпается сразу.

Проверяют так: getSupportedExtensions() возвращает разный состав у разных вендоров, плюс MAX_TEXTURE_SIZE и MAX_RENDERBUFFER_SIZE дают числа, привязанные к железу. Подменил строку, забыл про числа, получил нестыковку на ровном месте.

три монитора и ни одного свободного
Данила Р
Данила Р
Новичок
сообщений 145
с мар, второй сезон
22 августа, 17:55#5

а если просто заблокировать canvas расширением? вообще ничего не отдавать

dobrynin_a
dobrynin_a
Знаток
сообщений 1690
с апр
1 января, 08:12#6

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

Рабочий подход другой: шум. К изображению добавляется незаметный глазу сдвиг нескольких пикселей, хеш меняется, картинка остаётся прежней. Главное условие: шум постоянный внутри профиля и свой у каждого профиля.

gremlin_dv
gremlin_dv
Знаток
сообщений 1840
с мар
8 июня, 11:29#7

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

три монитора и ни одного свободного
byteflow
byteflow
Новичок
сообщений 225
с фев, второй сезон
15 ноября, 14:46#8

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

const h = () => {
  const c = document.createElement('canvas'), x = c.getContext('2d');
  x.font = '16px Arial';
  x.fillText('verstak', 2, 2);
  return c.toDataURL().slice(-24);
};
console.log(h(), h());

Пошёл искать переключатель.

dobrynin_a
dobrynin_a
Знаток
сообщений 1690
с апр
22 апреля, 17:03#9

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

Сколько разных хешей холста профиль отдаёт за один визит
Сколько разных хешей холста профиль отдаёт за один визит

Единица это норма, семёрка это красный флаг. Заодно проверь WebGL тем же способом, режим у него отдельный и про него забывают.

byteflow
byteflow
Новичок
сообщений 225
с фев, второй сезон
1 сентября, 08:20#10

Нашёл, стоял режим «на каждый вызов». Переключил на постоянный, два вызова подряд теперь дают одинаковый хвост, WebGL тоже перепроверил.

Строки вендора и рендерера сверил со списком расширений, там сходится. Спасибо, стало сильно понятнее.