Migrer vers les indicateurs client user-agent

Stratégies pour faire passer votre site de l'utilisation de la chaîne user-agent aux nouveaux indicateurs client User-Agent.

La chaîne User-Agent est une surface de fingerprinting passive importante dans les navigateurs, et elle est difficile à traiter. Cependant, il existe toutes sortes de raisons valides pour collecter et traiter les données des user-agents. Il faut donc trouver une meilleure solution. Les indicateurs client user-agent constituent à la fois un moyen explicite de déclarer que vous avez besoin de données user-agent et des méthodes pour les renvoyer dans un format facile à utiliser.

Cet article vous explique comment auditer votre accès aux données des user-agents et migrer l'utilisation des chaînes user-agent vers les indicateurs client User-Agent.

Auditer la collecte et l'utilisation des données des user-agents

Comme pour toute forme de collecte de données, vous devez toujours comprendre pourquoi vous les collectez. La première étape, que vous décidiez ou non d'effectuer une action, consiste à comprendre où et pourquoi vous utilisez les données des user-agents.

Si vous ne savez pas si ni où des données user-agent sont utilisées, envisagez de rechercher dans le code frontal pour utiliser navigator.userAgent, et dans le code backend pour utiliser l'en-tête HTTP User-Agent. Vous devez également vérifier que votre code frontal ne contient pas de fonctionnalités déjà obsolètes, telles que navigator.platform et navigator.appVersion.

D'un point de vue fonctionnel, pensez à l'endroit où vous enregistrez ou traitez dans votre code:

  • Nom ou version du navigateur
  • Nom ou version du système d'exploitation
  • Marque ou modèle de l'appareil
  • Type de processeur, architecture ou nombre de bits (par exemple, 64 bits)

Vous utilisez peut-être également une bibliothèque ou un service tiers pour traiter le user-agent. Dans ce cas, vérifiez s'ils sont mis à jour pour prendre en charge les indicateurs client user-agent.

Utilisez-vous uniquement des données de base des user-agents ?

L'ensemble par défaut d'indicateurs client user-agent comprend:

  • Sec-CH-UA: nom du navigateur et version majeure/significative
  • Sec-CH-UA-Mobile: valeur booléenne indiquant un appareil mobile.
  • Sec-CH-UA-Platform: nom du système d'exploitation
    • Notez que cette information a été mise à jour dans les spécifications et qu'elle sera adaptée dans Chrome et dans les autres navigateurs basés sur Chromium.

La version réduite de la chaîne user-agent proposée conservera également ces informations de base de manière rétrocompatible. Par exemple, au lieu de Chrome/90.0.4430.85, la chaîne doit inclure Chrome/90.0.0.0.

Si vous vérifiez uniquement le nom du navigateur, la version majeure ou le système d'exploitation dans la chaîne du user-agent, votre code continuera de fonctionner. Toutefois, vous risquez de voir des avertissements d'abandon.

Bien que vous puissiez et que vous deviez migrer vers les indicateurs client User-Agent, il est possible que des contraintes de code ou de ressources héritées vous empêchent de le faire. En réduisant la quantité d'informations contenues dans la chaîne user-agent de cette manière rétrocompatible, vous devez vous assurer que même si le code existant reçoit des informations moins détaillées, il doit conserver les fonctionnalités de base.

Stratégie: API JavaScript côté client à la demande

Si vous utilisez actuellement navigator.userAgent, vous devez passer à la préférence navigator.userAgentData avant de revenir à l'analyse de la chaîne user-agent.

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

Si vous vérifiez pour mobile ou ordinateur, utilisez la valeur booléenne mobile:

const isMobile = navigator.userAgentData.mobile;

userAgentData.brands est un tableau d'objets avec des propriétés brand et version, dans lequel le navigateur peut répertorier sa compatibilité avec ces marques. Vous pouvez y accéder directement en tant que tableau ou utiliser un appel some() pour vérifier si une entrée spécifique est présente:

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
}

Si vous avez besoin de l'une des valeurs de user-agent les plus détaillées et à entropie élevée, vous devez la spécifier et vérifier le résultat dans le Promise renvoyé:

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

Vous pouvez également utiliser cette stratégie si vous souhaitez passer du traitement côté serveur au traitement côté client. L'API JavaScript ne nécessite pas d'accès aux en-têtes de requête HTTP. Les valeurs user-agent peuvent donc être demandées à tout moment.

Stratégie: en-tête statique côté serveur

Si vous utilisez l'en-tête de requête User-Agent sur le serveur et que vos besoins concernant ces données sont relativement cohérents sur l'ensemble de votre site, vous pouvez spécifier les indications client souhaitées sous la forme d'un ensemble statique dans vos réponses. Cette approche est relativement simple, car vous ne devez généralement la configurer qu'à un seul emplacement. Par exemple, elle peut se trouver dans la configuration de votre serveur Web si vous y ajoutez déjà des en-têtes, votre configuration d'hébergement ou la configuration de premier niveau du framework ou de la plate-forme que vous utilisez pour votre site.

Envisagez cette stratégie si vous transformez ou personnalisez les réponses diffusées en fonction des données du user-agent.

Les navigateurs ou d'autres clients peuvent choisir de fournir différentes indications par défaut. Il est donc recommandé de spécifier tout ce dont vous avez besoin, même s'il est généralement fourni par défaut.

Par exemple, les valeurs par défaut actuelles pour Chrome seraient représentées comme suit:

⬇️ En-têtes de réponse

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

Si vous souhaitez également recevoir le modèle d'appareil dans les réponses, envoyez ce qui suit:

⬇️ En-têtes de réponse

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

Lors du traitement côté serveur, vous devez d'abord vérifier si l'en-tête Sec-CH-UA souhaité a été envoyé, puis utiliser l'analyse de l'en-tête User-Agent s'il n'est pas disponible.

Stratégie: déléguer des indices aux demandes multi-origines

Si vous demandez l'envoi de sous-ressources multi-origines ou intersites nécessitant l'envoi d'indicateurs client user-agent lors de leurs requêtes, vous devez spécifier explicitement les indices souhaités à l'aide de règles d'autorisation.

Par exemple, supposons que https://blog.site héberge des ressources sur https://cdn.site, ce qui peut renvoyer des ressources optimisées pour un appareil spécifique. https://blog.site peut demander l'indice Sec-CH-UA-Model, mais doit la déléguer explicitement à https://cdn.site à l'aide de l'en-tête Permissions-Policy. La liste des optimisations contrôlées par des règles est disponible dans le brouillon d'infrastructure des indicateurs client.

⬇️ Réponse de blog.site en déléguant l'indice

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

⬆️ Demande de sous-ressources sur cdn.site incluant l'indice délégué

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

Vous pouvez spécifier plusieurs indications pour plusieurs origines, et pas seulement à partir de la plage ch-ua:

⬇️ Réponse de blog.site déléguant plusieurs indices à plusieurs origines

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")

Stratégie: déléguer des astuces aux iFrames

Les iFrames multi-origines fonctionnent de la même manière que les ressources multi-origines, mais vous devez spécifier les indications que vous souhaitez déléguer dans l'attribut allow.

⬇️ Réponse de blog.site

Accept-CH: Sec-CH-UA-Model

↪️ HTML pour blog.site

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

⬆️ Demande de widget.site

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

L'attribut allow dans l'iFrame remplace tout en-tête Accept-CH que widget.site peut envoyer lui-même. Assurez-vous donc d'avoir spécifié tous les éléments nécessaires au site de l'iFrame.

Stratégie: indications dynamiques côté serveur

Si certaines parties du parcours utilisateur nécessitent un plus grand nombre d'indices que sur le reste du site, vous pouvez choisir de les demander à la demande plutôt que de manière statique sur l'ensemble du site. Cette méthode est plus complexe à gérer, mais si vous définissez déjà des en-têtes différents pour chaque route, cela peut être réalisable.

La chose importante à retenir ici est que chaque instance de l'en-tête Accept-CH écrasera efficacement l'ensemble existant. Ainsi, si vous définissez l'en-tête de manière dynamique, chaque page doit demander l'ensemble complet des indications requises.

Par exemple, vous pouvez disposer d'une section de votre site dans laquelle vous souhaitez fournir des icônes et des commandes correspondant au système d'exploitation de l'utilisateur. Pour ce faire, vous pouvez également extraire Sec-CH-UA-Platform-Version afin de diffuser les sous-ressources appropriées.

⬇️ En-têtes de réponse pour /blog

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

⬇️ En-têtes de réponse pour /app

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

Stratégie: indications côté serveur requises à la première requête

Il peut arriver que vous ayez besoin d'un ensemble d'indicateurs supérieur à l'ensemble par défaut lors de la toute première requête. Toutefois, comme cela est susceptible d'être rare, assurez-vous d'avoir examiné le raisonnement.

La première requête correspond en fait à la toute première requête de premier niveau pour cette origine, envoyée dans cette session de navigation. L'ensemble d'indicateurs par défaut comprend le nom du navigateur avec la version majeure, la plate-forme et l'indicateur de mobile. La question à se poser ici est donc la suivante : avez-vous besoin de données étendues lors du chargement initial de la page ?

Pour des indications supplémentaires sur la première requête, deux options s'offrent à vous. Tout d'abord, vous pouvez utiliser l'en-tête Critical-CH. Le format est le même que Accept-CH, mais il indique au navigateur qu'il doit relancer immédiatement la requête si la première a été envoyée sans l'indication critique.

⬆️ Demande initiale

[With default headers]

⬇️ En-têtes de réponse

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

🔃 Le navigateur relance la requête initiale avec l'en-tête supplémentaire.

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

Cela entraîne une surcharge liée à la nouvelle tentative lors de la toute première requête, mais le coût d'implémentation est relativement faible. Envoyez l'en-tête supplémentaire et le navigateur s'occupera du reste.

Dans les cas où vous avez vraiment besoin d'indications supplémentaires lors du tout premier chargement de la page, la proposition de fiabilité des indicateurs client définit une route permettant de spécifier des indications dans les paramètres de connexion. Cette opération utilise l'extension ALPS(Application-Layer Protocol Settings) vers TLS 1.3 pour permettre cette transmission anticipée d'indications sur les connexions HTTP/2 et HTTP/3. Nous n'en sommes qu'au tout début, mais si vous gérez activement vos propres paramètres TLS et de connexion, c'est le moment idéal pour apporter votre contribution.

Stratégie: ancienne prise en charge

Votre site peut contenir du code ancien ou tiers qui dépend de navigator.userAgent, y compris des parties de la chaîne user-agent qui seront réduites. À long terme, vous devez planifier de passer aux appels navigator.userAgentData équivalents, mais il existe une solution provisoire.

UA-CH rétrofill est une petite bibliothèque qui vous permet de remplacer navigator.userAgent par une nouvelle chaîne créée à partir des valeurs navigator.userAgentData demandées.

Par exemple, ce code génère une chaîne user-agent qui inclut également l'indication "modèle" :

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

La chaîne obtenue affiche le modèle Pixel 5, mais affiche toujours la valeur 92.0.0.0 réduite, car l'indice uaFullVersion n'a pas été demandé:

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

Assistance supplémentaire

Si ces stratégies ne couvrent pas votre cas d'utilisation, veuillez lancer une discussion dans le dépôt privacy-sandbox-dev-support afin que nous puissions examiner votre problème ensemble.

Photo par Ricardo Rocha sur Unsplash