Esegui la migrazione ai client hint dello user agent

Strategie per eseguire la migrazione del tuo sito dall'utilizzo della stringa user-agent ai nuovi client hint User-Agent.

La stringa User-Agent è una superficie di fingerprinting passivo significativa nei browser, oltre a essere difficile da elaborare. Tuttavia, esistono diversi motivi validi per raccogliere ed elaborare i dati degli agenti utente, quindi è necessario trovare un percorso per una soluzione migliore. Gli indicatori client dell'agente utente forniscono sia un modo esplicito per dichiarare la tua necessità di dati dell'agente utente sia metodi per restituire i dati in un formato facile da usare.

Questo articolo illustra come eseguire il controllo dell'accesso ai dati dello user agent ed eseguire la migrazione dell'utilizzo della stringa dello user agent ai client hint dello user agent.

Controllare la raccolta e l'utilizzo dei dati degli user agent

Come per qualsiasi forma di raccolta dei dati, devi sempre capire perché li stai raccogliendo. Il primo passaggio, indipendentemente dal fatto che tu intraprenda o meno un'azione, è capire dove e perché utilizzi i dati dello user agent.

Se non sai se o dove vengono utilizzati i dati dello user-agent, ti consigliamo di cercare nel codice frontend l'utilizzo di navigator.userAgent e nel codice back-end l'utilizzo dell'intestazione HTTP User-Agent. Inoltre, devi verificare se nel codice frontend sono presenti funzionalità già ritirate, come navigator.platform e navigator.appVersion.

Da un punto di vista funzionale, pensa a qualsiasi punto del codice in cui effettui la registrazione o l'elaborazione:

  • Nome o versione del browser
  • Nome o versione del sistema operativo
  • Marca o modello del dispositivo
  • Tipo, architettura o accoppiamento a bit della CPU (ad esempio 64 bit)

È inoltre probabile che tu stia utilizzando una libreria o un servizio di terze parti per elaborare l'user-agent. In questo caso, controlla se sono in corso aggiornamenti per supportare i client hint User-Agent.

Utilizzi solo dati di base dell'agente utente?

L'insieme predefinito di User-Agent client hints include:

  • Sec-CH-UA: nome del browser e versione principale/significativa
  • Sec-CH-UA-Mobile: valore booleano che indica un dispositivo mobile
  • Sec-CH-UA-Platform: nome del sistema operativo
    • Tieni presente che questa funzionalità è stata aggiornata nella specifica e verrà applicata a breve in Chrome e in altri browser basati su Chromium.

La versione ridotta della stringa user-agent proposta manterrà anche queste informazioni di base in modo compatibile con le versioni precedenti. Ad esempio, anziché Chrome/90.0.4430.85 la stringa includerebbe Chrome/90.0.0.0.

Se controlli la stringa dello user agent solo per il nome del browser, la versione principale o il sistema operativo, il codice continuerà a funzionare, anche se è probabile che visualizzi avvisi di ritiro.

Sebbene tu possa ed debba eseguire la migrazione ai client hint User-Agent, potresti avere vincoli di risorse o codice legacy che lo impediscono. La riduzione delle informazioni nella stringa dell'agente utente in questo modo compatibile con le versioni precedenti ha lo scopo di garantire che, anche se il codice esistente riceverà informazioni meno dettagliate, debba comunque mantenere la funzionalità di base.

Strategia: API JavaScript lato client on demand

Se al momento utilizzi navigator.userAgent, devi eseguire la transizione per dare la preferenza a navigator.userAgentData prima di eseguire il parsing della stringa user-agent.

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

Se stai verificando la presenza di dispositivi mobili o computer, utilizza il valore booleano mobile:

const isMobile = navigator.userAgentData.mobile;

userAgentData.brands è un array di oggetti con proprietà brand e version in cui il browser è in grado di elencare la propria compatibilità con questi brand. Puoi accedervi direttamente come array o utilizzare una chiamata some() per verificare se è presente una voce specifica:

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
}

Se hai bisogno di uno dei valori dello user agent più dettagliati e con alta entropia, dovrai specificarlo e controllare il risultato nel valore Promise restituito:

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

Ti consigliamo di utilizzare questa strategia anche se vuoi passare dall'elaborazione lato server all'elaborazione lato client. L'API JavaScript non richiede l'accesso alle intestazioni delle richieste HTTP, pertanto i valori dello user agent possono essere richiesti in qualsiasi momento.

Strategia: intestazione lato server statica

Se utilizzi l'intestazione di richiesta User-Agent sul server e le tue esigenze per questi dati sono relativamente coerenti nell'intero sito, puoi specificare gli indicatori client desiderati come insieme statico nelle risposte. Si tratta di un approccio relativamente semplice, poiché in genere è sufficiente configurarlo in un'unica posizione. Ad esempio, potrebbe trovarsi nella configurazione del server web se aggiungi già le intestazioni, nella configurazione dell'hosting o nella configurazione di primo livello del framework o della piattaforma che utilizzi per il tuo sito.

Valuta questa strategia se stai trasformando o personalizzando le risposte pubblicate in base ai dati dell'agente utente.

I browser o altri client possono scegliere di fornire diversi suggerimenti predefiniti, quindi è buona prassi specificare tutto ciò che ti serve, anche se in genere viene fornito per impostazione predefinita.

Ad esempio, i valori predefiniti correnti per Chrome verranno rappresentati come:

⬇️ Intestazioni di risposta

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

Se vuoi ricevere anche il modello del dispositivo nelle risposte, devi inviare:

⬇️ Intestazioni delle risposte

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

Durante l'elaborazione sul lato server, devi prima controllare se l'intestazione Sec-CH-UA desiderata è stata inviata, quindi utilizzare l'analisi dell'intestazione User-Agent se non è disponibile.

Strategia: delega dei suggerimenti alle richieste multiorigine

Se richiedi risorse secondarie cross-origin o cross-site che richiedono l'invio di client hint User-Agent nelle loro richieste, dovrai specificare esplicitamente i hint desiderati utilizzando un criterio di autorizzazione.

Ad esempio, supponiamo che https://blog.site ospiti risorse su https://cdn.site che possono restituire risorse ottimizzate per un dispositivo specifico. https://blog.site può richiedere il suggerimento Sec-CH-UA-Model, ma deve delegarlo esplicitamente a https://cdn.site utilizzando l'intestazione Permissions-Policy. L'elenco di suggerimenti controllati dai criteri è disponibile nella bozza dell'Infrastruttura Client Hints

⬇️ Risposta di blog.site che delega l'indizio

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

⬆️ La richiesta alle risorse secondarie su cdn.site deve includere l'indicazione delegata

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

Puoi specificare più suggerimenti per più origini e non solo dall'intervallo ch-ua:

⬇️ Risposta da blog.site che delega più suggerimenti a più origini

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

Strategia: delega dei suggerimenti agli iframe

Gli iframe cross-origin funzionano in modo simile alle risorse cross-origin, ma devi specificare i suggerimenti da delegare nell'attributo allow.

⬇️ Risposta da blog.site

Accept-CH: Sec-CH-UA-Model

↪️ HTML per blog.site

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

⬆️ Richiesta a widget.site

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

L'attributo allow nell'iframe sostituisce qualsiasi intestazione Accept-CH che widget.site può inviare automaticamente, quindi assicurati di aver specificato tutto ciò di cui il sito ha bisogno per il sito iframe.

Strategia: suggerimenti lato server dinamici

Se in alcune parti specifiche del percorso dell'utente hai bisogno di una selezione più ampia di suggerimenti rispetto al resto del sito, puoi scegliere di richiederli su richiesta anziché in modo statico nell'intero sito. Questa operazione è più complessa da gestire, ma se hai già impostato intestazioni diverse in base alla route, potrebbe essere fattibile.

È importante ricordare che ogni istanza dell'intestazione Accept-CH sovrascriverà in modo efficace il set esistente. Pertanto, se imposti dinamicamente l'intestazione, ogni pagina deve richiedere l'intero insieme di suggerimenti richiesti.

Ad esempio, potresti avere una sezione sul tuo sito in cui vuoi fornire icone e controlli corrispondenti al sistema operativo dell'utente. Per questo, potresti anche includere Sec-CH-UA-Platform-Version per pubblicare risorse secondarie appropriate.

⬇️ Intestazioni delle risposte per /blog

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

⬇️ Intestazioni della risposta per /app

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

Strategia: suggerimenti lato server obbligatori alla prima richiesta

In alcuni casi potresti aver bisogno di più dell'insieme predefinito di suggerimenti per la prima richiesta, ma è probabile che si tratti di casi rari, quindi assicurati di aver esaminato il ragionamento.

Con la prima richiesta si intende in realtà la prima richiesta di primo livello per quell'origine inviata durante quella sessione di navigazione. L'insieme di suggerimenti predefinito include il nome del browser con la versione principale, la piattaforma e l'indicatore di dispositivo mobile. La domanda da porti a questo punto è: Avete bisogno di dati estesi durante il caricamento iniziale della pagina?

Per ulteriori suggerimenti sulla prima richiesta, hai due opzioni. Innanzitutto, puoi utilizzare l'intestazione Critical-CH. Ha lo stesso formato di Accept-CH, ma indica al browser di riprovare immediatamente la richiesta se la prima è stata inviata senza l'indizio critico.

⬆️ Richiesta iniziale

[With default headers]

⬇️ Intestazioni di risposta

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

🔃 Il browser riprova la richiesta iniziale con l'intestazione aggiuntiva

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

Ciò comporterà l'overhead del nuovo tentativo sulla primissima richiesta, ma il costo di implementazione è relativamente basso. Invia l'intestazione aggiuntiva e il browser farà il resto.

Per le situazioni in cui hai davvero bisogno di suggerimenti aggiuntivi al primo caricamento della pagina, la proposta relativa all'affidabilità dei suggerimenti client prevede un percorso per specificare i suggerimenti nelle impostazioni a livello di connessione. Ciò utilizza l'estensione Application- Layer Protocol Settings(ALPS) a TLS 1.3 per consentire il passaggio anticipato dei suggerimenti sulle connessioni HTTP/2 e HTTP/3. Questa funzionalità è ancora in una fase molto iniziale, ma se gestisci attivamente le tue impostazioni TLS e di connessione, questo è il momento ideale per dare il tuo contributo.

Strategia: supporto legacy

Sul tuo sito potresti avere codice precedente o di terze parti che dipende da navigator.userAgent, incluse parti della stringa dell'user-agent che verranno ridotte. A lungo termine, dovresti pianificare il passaggio alle chiamate navigator.userAgentData equivalenti, ma esiste una soluzione provvisoria.

UA-CH retrofill è una piccola biblioteca che consente di sovrascrivere navigator.userAgent con una nuova stringa creata dai valori navigator.userAgentData richiesti.

Ad esempio, questo codice genera una stringa user agent che include anche il suggerimento "model":

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

La stringa risultante mostrerà il modello Pixel 5, ma continuerà a mostrare il valore ridotto92.0.0.0 poiché l'indicazione uaFullVersion non è stata richiesta:

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

Ulteriore assistenza

Se queste strategie non coprono il tuo caso d'uso, avvia una discussione nel repo privacy-sandbox-dev-support e possiamo esaminare insieme il problema.

Foto di Ricardo Rocha su Unsplash