Chrome тестирует API, рисующий настоящий HTML на canvas. Разбираем, что предложение исключает из пикселей и что оставляет читаемым.
Chrome экспериментирует с API, которое позволяет <canvas> рисовать не только линии, прямоугольники и строки текста, но и настоящий стилизованный HTML. Сразу возникает вопрос о приватности: пиксели холста можно прочитать обратно, а чтение пикселей — основа Canvas-фингерпринтинга. Если на холсте теперь может оказаться отрисованная страница, что из неё сможет вытащить скрипт? Авторы предложения отвечают конкретным списком того, что рисовать нельзя ни при каких условиях. Эта статья разбирает список и то, о чём он говорит. Это эксперимент, а не выпущенная функция.
Главное
- HTML-in-Canvas — предложение в origin trial Chrome, а не принятый веб-стандарт. По собственной статье Chrome, испытание идёт до Chrome 160, а названия методов уже менялись (например, в Chrome 155).
- Основное правило приватности — «read-back-allowed rendering»: отрисовка элемента не должна раскрывать ничего чувствительного, чего код страницы и так не мог бы наблюдать.
- Пояснительный документ исключает из нарисованного кросс-доменное содержимое, системные цвета и темы, маркеры орфографии, состояние посещённых ссылок, ожидающее автозаполнение и субпиксельное сглаживание текста.
- Он намеренно оставляет то, что считает и так обнаруживаемым: вид полос прокрутки и элементов форм, частоту мигания каретки и
forced-colors. - Это не существующая сегодня техника фингерпринтинга, а дизайн, который старается не создавать новую.
Что делает API
Сегодня холст рисует примитивы. Строку можно вывести через fillText(), но стилизованный <div> с вёрсткой, переносами и элементами формы ему не передать. Предложение HTML-in-Canvas, которое развивается в репозитории WICG, добавляет возможность делать снимок элемента и рисовать его в 2D-, WebGL- и WebGPU-холстах; для 2D метод называется drawElementImage(). В статье Chrome об изменениях origin trial сказано, что испытание продлено до Chrome 160, а некоторые методы и атрибуты были переименованы в Chrome 155, так что любой код — предварительный. У функции есть и запись в Chrome Platform Status.
Мотивация в основном творческая и практическая: эффекты над настоящим HTML, текст в 3D-сценах, доступное содержимое внутри холста. Приватность здесь — ограничение дизайна, а не цель.
Почему холст — чувствительная поверхность
Холст — не только вывод. Скрипт может вызвать toDataURL() или getImageData() и получить каждый пиксель как данные. Именно так работает Canvas-фингерпринтинг: рисуют фиксированную сцену, читают её и хешируют. Хеш различается, потому что различаются GPU, драйверы, растеризаторы шрифтов и ОС. Общую картину см. в нашем руководстве по фингерпринтингу браузера.
Теперь представьте холст, который может содержать отрисованную страницу. Браузер рисует то, что скрипт страницы напрямую не видит: посещена ли ссылка, какого цвета тема ОС, подчеркнуло ли слово средство проверки орфографии. Если бы это просочилось в нарисованные пиксели, скрипт мог бы прочитать это обратно, и безобидный вызов рисования стал бы окном в приватное состояние.
Правило «read-back-allowed»
Пояснительный документ решает проблему одним принципом, который называет read-back-allowed rendering. По его формулировке, отрисовка элемента и связанное событие paint «не должны раскрывать никакой чувствительной с точки зрения безопасности или приватности информации, которая иначе недоступна коду автора». Поскольку чтение пикселей с WebGL и WebGPU возможно всегда, надёжный путь — изначально не помещать чувствительное в вывод. Документ говорит о предотвращении утечек через чтение пикселей, атаки по времени и события инвалидации. Слово «фингерпринтинг» в нём не встречается: это правило безопасности и приватности, а прочтение через фингерпринтинг ниже — наше.
Что исключено из пикселей
Документ перечисляет то, что нужно исключить из отрисовки:
- Кросс-доменные данные во встроенном содержимом (iframe, изображения), в URL-ссылках вроде
background-image, в холстах, «загрязнённых» кросс-доменными данными, и в ссылках SVG. iframe с того же источника по-прежнему отрисовываются, а кросс-доменное содержимое внутри них — нет. - Системные цвета, темы и настройки.
- Маркеры орфографии и грамматики.
- Информация о посещённых ссылках.
- Ожидающее автозаполнение форм, которое иначе недоступно JavaScript.
- Субпиксельное сглаживание текста.
- Субтитры и элементы управления видео.
- Всплывающие окна IME и характерное форматирование текста IME.
Большинство пунктов — очевидные кандидаты на утечку (посещённые ссылки и автозаполнение — классические цели для «сниффинга» истории). Для фингерпринтинга интереснее всего субпиксельное сглаживание. То, как платформа сглаживает края символов, зависит от ОС, дисплея и настроек — отчасти поэтому один и тот же текст на разных машинах выглядит чуть по-разному. Обычный fillText() на холсте уже раскрывает значительную часть этого поведения, и оно служит основой фингерпринтинга шрифтов и отрисовки текста. Исключив его из нового пути, предложение не добавляет нового способа прочитать это с более высоким разрешением.
Контраст важен: предложение не исправляет существующий Canvas-фингерпринтинг, оно лишь отказывается расширять поверхность.
Что намеренно оставлено
Документ также перечисляет то, что в этом контексте не считает чувствительным:
- маркеры поиска по странице и text-fragment;
- вид полос прокрутки и элементов форм, которые, по его словам, уже обнаруживаются в Blink и WebKit через
foreignObject; - частота мигания каретки;
forced-colors, который, как отмечено, уже доступен JavaScript через медиазапрос и системные цвета.
Логика последовательна: если код страницы и так видит значение, его отрисовка не добавляет информации. Правило разумное, но показывает и предел. Сигналы вроде forced-colors уже входят в то, что собирает фингерпринтинг через CSS-медиазапросы, так что трекеры получат их в любом случае. Предложение не обещает их уменьшить.
Пути через GPU
Та же проблема чтения есть и на стороне GPU: документ прямо говорит, что чтение пикселей с WebGL и WebGPU возможно всегда. Поэтому правила исключения распространяются и на варианты, рисующие снимки элементов в эти контексты: сейчас это texElementSubImage2D() для WebGL и drawElementImageToTexture() для WebGPU — оба названия появились в Chrome 155. О том, что эти контексты раскрывают и так, см. разбор WebGL-фингерпринтинга и WebGPU-фингерпринтинг.
Честные ограничения
- Это предложение и эксперимент. Испытание Chrome может измениться или завершиться, а проверка на приватность может изменить список исключений.
- На цитируемых нами страницах мы не нашли обязательств других движков, поэтому ничего не утверждаем о позиции Firefox или Safari.
- Правило в проектном документе настолько хорошо, насколько хороша реализация. Пограничные случаи (тайминг, инвалидация, необычные типы элементов) — именно те места, где такие правила обычно протекают; поэтому документ прямо называет атаки по времени.
- Ничто из этого не меняет того, что Canvas-фингерпринтинг умеет сегодня.
Что это значит для вас
Для посетителей: сейчас ничего не меняется. Origin trial работает только на сайтах, которые зарегистрировались в нём, и только в версиях Chrome внутри окна испытания; сами вы его не включаете. Если хотите снизить риск Canvas-фингерпринтинга в любом случае, прочитайте, как шум и рандомизация canvas могут сыграть против вас, и выбирайте единообразие, а не случайность.
Для разработчиков: если экспериментируете с API, считайте названия временными и не рассчитывайте захватывать в холст чувствительное состояние — так задумано.
Проверьте свой Canvas-хеш
Проверка отпечатка BrowserInsight считает Canvas-хеш стандартным 2D-API и не использует HTML-in-Canvas. Это хороший способ увидеть, что скрипт, читающий обычный холст, получает от вашего браузера уже сегодня.


