Переход на клиентские подсказки User-Agent

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

Опубликовано: 19 мая 2021 г.

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

Здесь мы покажем вам аудит вашего доступа к данным пользовательского агента и перенос использования строки пользовательского агента в клиентские подсказки пользовательского агента.

Browser Support

  • Хром: 90.
  • Край: 90.
  • Firefox: не поддерживается.
  • Сафари: не поддерживается.

Source

Аудит сбора и использования данных пользовательского агента

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

Если вы не знаете, используются ли или где данные пользовательского агента, рассмотрите возможность поиска в коде внешнего интерфейса использования navigator.userAgent и в внутреннем коде для использования HTTP-заголовка User-Agent . Вам также следует проверить код внешнего интерфейса на предмет использования уже устаревших функций, таких как navigator.platform и navigator.appVersion .

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

  • Название или версия браузера
  • Название или версия операционной системы
  • Марка или модель устройства
  • Тип процессора, архитектура или разрядность (например, 64-разрядный)

Также вероятно, что вы используете стороннюю библиотеку или службу для обработки пользовательского агента. В этом случае проверьте, обновляются ли они для поддержки подсказок клиента User-Agent.

Вы используете только основные данные пользовательского агента?

Набор клиентских подсказок User-Agent по умолчанию включает в себя:

  • Sec-CH-UA : имя браузера и основная/значительная версия.
  • Sec-CH-UA-Mobile : логическое значение, указывающее мобильное устройство.
  • Sec-CH-UA-Platform : имя операционной системы.

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

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

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

Стратегии

Существует ряд стратегий, которые можно использовать для переноса использования строки пользовательского агента на подсказки клиента пользовательского агента.

API JavaScript на стороне клиента по требованию

Если вы используете navigator.userAgent , вам следует перейти к предпочтению navigator.userAgentData , прежде чем вернуться к анализу строки пользовательского агента.

if (navigator.userAgentData) {
  // use new hints
} else {
  // fall back to user-agent string parsing
}

Если вы проверяете мобильный или настольный компьютер, используйте логическое значение mobile :

const isMobile = navigator.userAgentData.mobile;

userAgentData.brands — это массив объектов со свойствами brand и version , в котором браузер может указать свою совместимость с этими брендами. Вы можете получить к нему доступ напрямую как к массиву или можете использовать вызов some() , чтобы проверить наличие определенной записи:

function isCompatible(item) {
  // In real life you most likely have more complex rules here
  return ['Chromium', 'Google Chrome', 'NewBrowser'].includes(item.brand);
}
if (navigator.userAgentData.brands.some(isCompatible)) {
  // browser reports as compatible
}

Если вам нужно одно из более подробных значений пользовательского агента с высокой энтропией, вам нужно указать его и проверить результат в возвращенном Promise :

navigator.userAgentData.getHighEntropyValues(['model'])
  .then(ua => {
    // requested hints available as attributes
    const model = ua.model
  });

Вы также можете использовать эту стратегию, если хотите перейти от обработки на стороне сервера к обработке на стороне клиента. API JavaScript не требует доступа к заголовкам HTTP-запросов, поэтому значения пользовательского агента можно запросить в любой момент.

Статический заголовок на стороне сервера

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

Рассмотрите эту стратегию, если вы преобразуете или настраиваете ответы, предоставляемые на основе данных пользовательского агента.

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

Например, текущие значения по умолчанию для Chrome будут представлены как:

⬇️ Заголовки ответов

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

Если бы вы также хотели получать в ответах модель устройства, то вы бы отправили:

⬇️ Заголовки ответов

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA

При обработке этого на стороне сервера вам следует сначала проверить, был ли отправлен желаемый заголовок Sec-CH-UA , а затем вернуться к анализу заголовка User-Agent если он недоступен.

Делегирование подсказок для запросов из разных источников

Если вы запрашиваете подресурсы из разных источников или между сайтами, для которых требуется отправка подсказок клиента User-Agent по их запросам, вам необходимо будет явно указать нужные подсказки с помощью политики разрешений .

Например, предположим, что https://blog.site размещает ресурсы на https://cdn.site , которые могут возвращать ресурсы, оптимизированные для конкретного устройства. https://blog.site может запросить подсказку Sec-CH-UA-Model , но должен явно делегировать ее https://cdn.site , используя заголовок Permissions-Policy . Список подсказок, управляемых политикой, доступен в проекте инфраструктуры подсказок Clients Hints.

⬇️ Ответ сайта blog.site с делегированием подсказки

Accept-CH: Sec-CH-UA-Model
Permissions-Policy: ch-ua-model=(self "https://cdn.site")

⬆️ Запрос на подресурсы на cdn.site , включающий делегированную подсказку.

Sec-CH-UA-Model: "Pixel 5"

Вы можете указать несколько подсказок для нескольких источников, а не только из диапазона ch-ua :

⬇️ Ответ от blog.site делегирующий несколько подсказок нескольким источникам.

Accept-CH: Sec-CH-UA-Model, DPR
Permissions-Policy: ch-ua-model=(self "https://cdn.site"),
                    ch-dpr=(self "https://cdn.site" "https://img.site")

Делегирование подсказок для iframe

iframe из разных источников работают аналогично ресурсам из разных источников, но вы указываете подсказки, которые хотите делегировать, в allow .

⬇️ Ответ с blog.site

Accept-CH: Sec-CH-UA-Model

↪️ HTML для blog.site

<iframe src="https://widget.site" allow="ch-ua-model"></iframe>

⬆️ Запрос на widget.site

Sec-CH-UA-Model: "Pixel 5"

allow в iframe переопределит любой заголовок Accept-CH , который widget.site может отправить сам, поэтому убедитесь, что вы указали все, что понадобится сайту iframe.

Динамические подсказки на стороне сервера

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

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

Например, на вашем сайте может быть один раздел, в котором вы хотите разместить значки и элементы управления, соответствующие операционной системе пользователя. Для этого вы можете дополнительно подключить Sec-CH-UA-Platform-Version для обслуживания соответствующих подресурсов.

⬇️ Заголовки ответов для /blog

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

⬇️ Заголовки ответов для /app

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA

Адресные подсказки на стороне сервера требуются при первом запросе

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

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

Для дополнительных подсказок по первому запросу есть два варианта. Во-первых, вы можете использовать заголовок Critical-CH . Он имеет тот же формат, что и Accept-CH но сообщает браузеру, что он должен немедленно повторить запрос, если первый был отправлен без критической подсказки.

⬆️ Первоначальный запрос

[With default headers]

⬇️ Заголовки ответов

Accept-CH: Sec-CH-UA-Model
Critical-CH: Sec-CH-UA-Model

🔃 Браузер повторяет первоначальный запрос с дополнительным заголовком.

[With default headers + …]
Sec-CH-UA-Model: Pixel 5

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

В ситуациях, когда вам действительно требуются дополнительные подсказки при самой первой загрузке страницы, предложение Client Hints Reliability прокладывает путь для указания подсказок в настройках уровня соединения. При этом используется расширение настроек протокола уровня приложений (ALPS) для TLS 1.3, чтобы обеспечить раннюю передачу подсказок при соединениях HTTP/2 и HTTP/3. Это все еще находится на очень ранней стадии, но если вы активно управляете собственными настройками TLS и подключения, то это идеальное время, чтобы внести свой вклад.

Устаревшая поддержка

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

Retrofill UA-CH — это небольшая библиотека, которая позволяет перезаписывать navigator.userAgent новой строкой, созданной на основе запрошенных значений navigator.userAgentData .

Например, этот код генерирует строку пользовательского агента, которая дополнительно включает подсказку «модель»:

import { overrideUserAgentUsingClientHints } from './uach-retrofill.js';
overrideUserAgentUsingClientHints(['model'])
  .then(() => { console.log(navigator.userAgent); });

Результирующая строка будет отображать модель Pixel 5 , но по-прежнему будет отображать уменьшенную 92.0.0.0 поскольку подсказка uaFullVersion не запрашивалась:

Mozilla/5.0 (Linux; Android 10.0; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.0.0 Mobile Safari/537.36

Дальнейшая поддержка

Если эти стратегии не подходят для вашего варианта использования, начните обсуждение в репозитории Privacy-Sandbox-dev-support, и мы сможем вместе изучить вашу проблему.