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, nonché 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 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 voglia o meno intraprendere un'azione, è capire dove e perché utilizzi i dati degli 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 backend l'utilizzo dell'intestazione HTTP User-Agent. Inoltre, devi verificare che nel codice frontend non siano presenti funzionalità già ritirate, come navigator.platform e navigator.appVersion.

Da un punto di vista funzionale, pensa a qualsiasi punto del codice in cui stai registrando o elaborando:

  • 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, invece di 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 sua 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 user-agent più dettagliati e ad alta entropia, dovrai specificarlo e controllare il risultato in 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, pertanto è 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 anche ricevere il modello del dispositivo nelle risposte, invia:

⬇️ Intestazioni di risposta

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

Quando esegui l'elaborazione lato server, devi prima controllare se è stato inviato l'header Sec-CH-UA desiderato e poi eseguire il fallback all'analisi dell'header User-Agent se non è disponibile.

Strategia: delegare i suggerimenti alle richieste cross-origin

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 per l'intervallo ch-ua:

⬇️ Risposta di 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 di 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 sostituirà qualsiasi intestazione Accept-CH che widget.site potrebbe inviare, quindi assicurati di aver specificato tutto ciò di cui il sito dell'iframe avrà bisogno.

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.

La cosa importante da ricordare qui è che ogni istanza dell'Accept-CH header sovrascriverà effettivamente l'insieme 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 della risposta 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.

Per prima richiesta si intende la prima richiesta di primo livello per quell'origine inviata nella 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. Quindi la domanda da porsi è: hai bisogno di dati estesi sul 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. Per farlo, viene utilizzata l'estensione Application-Layer Protocol Settings(ALPS) per 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 l'indicazione "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