Estratégias para migrar seu site da dependência da string do user agent para as novas dicas de cliente HTTP do user agent.
A string do user agent é uma plataforma de impressão digital passiva significativa em navegadores, além de ser difícil de processar. No entanto, há vários motivos válidos para coletar e processar dados do user agent. Portanto, o que é necessário é um caminho para uma solução melhor. As dicas de cliente HTTP do user agent oferecem uma maneira explícita de declarar sua necessidade de dados e métodos do user agent para retornar os dados em um formato fácil de usar.
Neste artigo, vamos mostrar como auditar seu acesso aos dados do user agent e migrar o uso da string dele para as dicas de cliente do user agent.
Coleta e uso de dados do user agent
Como acontece com qualquer forma de coleta de dados, é preciso entender sempre por que você está coletando esses dados. A primeira etapa, independentemente de você realizar ou não qualquer ação, é entender onde e por que você está usando dados do user agent.
Se você não souber se ou onde os dados do user agent estão sendo usados, pesquise
seu código de front-end para usar navigator.userAgent
e seu código de back-end para
usar o cabeçalho HTTP User-Agent
. Verifique também seu código de front-end
para usar recursos já descontinuados, como navigator.platform
e
navigator.appVersion
.
De um ponto de vista funcional, pense em qualquer lugar do código em que você esteja gravando ou processando:
- Nome ou versão do navegador
- Nome ou versão do sistema operacional
- Marca ou modelo do dispositivo
- tipo de CPU, arquitetura ou quantidade de bits (por exemplo, 64 bits)
Também é provável que você esteja usando uma biblioteca ou um serviço de terceiros para processar o user agent. Nesse caso, verifique se eles estão sendo atualizados para oferecer suporte a dicas de cliente HTTP do user agent.
Você está usando apenas dados básicos do user agent?
O conjunto padrão de dicas de cliente HTTP do user agent inclui:
Sec-CH-UA
: nome do navegador e versão principal/significativa.Sec-CH-UA-Mobile
: valor booleano que indica um dispositivo móvel.Sec-CH-UA-Platform
: nome do sistema operacional- Isso foi atualizado na especificação e será refletido no Chrome e em outros navegadores baseados no Chromium em breve.
A versão reduzida da string do user agent proposta também vai manter
essas informações básicas de maneira compatível com versões anteriores. Por exemplo, em vez de
Chrome/90.0.4430.85
, a string incluiria Chrome/90.0.0.0
.
Se você estiver verificando apenas a string do user agent para o nome do navegador, a versão principal ou o sistema operacional, seu código continuará funcionando, mas é provável que você receba avisos de descontinuação.
Embora você possa e deva migrar para as dicas de cliente HTTP do user agent, você pode ter restrições de código ou recursos legados que impedem isso. A redução de informações na string do user agent dessa maneira compatível com versões anteriores tem como objetivo garantir que o código atual receba informações menos detalhadas, mas ainda mantenha a funcionalidade básica.
Estratégia: API JavaScript sob demanda do lado do cliente
Se você estiver usando navigator.userAgent
, faça a transição para
preferir navigator.userAgentData
antes de voltar à análise da
string do user agent.
if (navigator.userAgentData) {
// use new hints
} else {
// fall back to user-agent string parsing
}
Se você estiver verificando dispositivos móveis ou computadores, use o valor booleano mobile
:
const isMobile = navigator.userAgentData.mobile;
userAgentData.brands
é uma matriz de objetos com as propriedades brand
e version
em que o navegador pode listar a compatibilidade com essas
marcas. É possível acessá-lo diretamente como uma matriz ou usar uma chamada some()
para verificar se uma entrada específica está presente:
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 você precisar de um dos valores de user agent mais detalhados e de alta entropia, será
preciso especificá-lo e verificar o resultado no Promise
retornado:
navigator.userAgentData.getHighEntropyValues(['model'])
.then(ua => {
// requested hints available as attributes
const model = ua.model
});
Essa estratégia também pode ser útil se você quiser migrar do processamento do lado do servidor para o processamento do cliente. A API JavaScript não exige acesso a cabeçalhos de solicitação HTTP. Portanto, os valores do user agent podem ser solicitados a qualquer momento.
Estratégia: cabeçalho estático do lado do servidor
Se você estiver usando o cabeçalho de solicitação User-Agent
no servidor e suas necessidades
para esses dados forem relativamente consistentes em todo o site, será possível
especificar as dicas de cliente desejadas como um conjunto estático nas suas respostas. Essa é uma
abordagem relativamente simples, porque geralmente você só precisa configurá-la em um
local. Por exemplo, isso pode estar na configuração do servidor da Web se você já tiver adicionado cabeçalhos, a configuração de hospedagem ou a configuração de nível superior da estrutura ou plataforma usada para o site.
Considere essa estratégia se você estiver transformando ou personalizando as respostas veiculadas com base nos dados do user agent.
Navegadores ou outros clientes podem fornecer dicas padrão diferentes. Portanto, é recomendável especificar tudo o que você precisa, mesmo que ele seja fornecido por padrão.
Por exemplo, os padrões atuais do Chrome seriam representados como:
⬇️ Cabeçalhos de resposta
Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA
Se você também quiser receber o modelo do dispositivo nas respostas, envie:
⬇️ Cabeçalhos de resposta
Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA
Ao processar isso no lado do servidor, primeiro verifique se o cabeçalho
Sec-CH-UA
desejado foi enviado e, em seguida, substitua pela análise de cabeçalho User-Agent
se ele não estiver disponível.
Estratégia: delegar dicas a solicitações de diferentes origens
Se você estiver solicitando sub-recursos de origem cruzada ou entre sites que exigem o envio de dicas de cliente HTTP do user agent nas solicitações, será necessário especificar explicitamente as dicas desejadas usando uma política de permissões.
Por exemplo, digamos que https://blog.site
hospede recursos em
https://cdn.site
, que pode retornar recursos otimizados para um dispositivo específico.
https://blog.site
pode pedir a dica Sec-CH-UA-Model
, mas precisa
delegá-la explicitamente a https://cdn.site
usando o cabeçalho
Permissions-Policy
. A lista de dicas controladas por políticas está disponível no rascunho de infraestrutura de dicas de clientes (em inglês)
⬇️ Resposta de blog.site
delegando a dica
Accept-CH: Sec-CH-UA-Model
Permissions-Policy: ch-ua-model=(self "https://cdn.site")
⬆️ A solicitação de sub-recursos em cdn.site
inclui a dica delegada
Sec-CH-UA-Model: "Pixel 5"
Você pode especificar várias dicas para diversas origens, e não apenas no intervalo ch-ua
:
⬇️ Resposta de blog.site
delegando várias dicas a várias origens
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")
Estratégia: delegar dicas a iframes
Os iframes de origem cruzada funcionam de maneira semelhante aos recursos de origem cruzada, mas
você especifica as dicas que quer delegar no atributo allow
.
⬇️ Resposta de blog.site
Accept-CH: Sec-CH-UA-Model
↪️ HTML de blog.site
<iframe src="https://widget.site" allow="ch-ua-model"></iframe>
⬆️ Solicitação para widget.site
Sec-CH-UA-Model: "Pixel 5"
O atributo allow
no iframe substitui qualquer cabeçalho Accept-CH
que o widget.site
enviar. Portanto, verifique se você especificou tudo o que o site com iframe precisa.
Estratégia: dicas dinâmicas do lado do servidor
Se você tem partes específicas da jornada do usuário em que precisa de uma seleção maior de dicas do que no restante do site, pode solicitar essas dicas sob demanda, e não estaticamente em todo o site. Isso é mais complexo de gerenciar, mas se você já definiu cabeçalhos diferentes para cada rota, isso pode ser viável.
É importante lembrar que cada instância do cabeçalho Accept-CH
substituirá efetivamente o conjunto existente. Portanto, se você estiver definindo o cabeçalho dinamicamente, cada página precisará solicitar o conjunto completo de dicas necessárias.
Por exemplo, é possível ter uma seção no seu site em que você quer fornecer
ícones e controles que correspondem ao sistema operacional do usuário. Para isso, convém
extrair ainda mais o Sec-CH-UA-Platform-Version
para exibir sub-recursos
adequados.
⬇️ Cabeçalhos de resposta para /blog
Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA
⬇️ Cabeçalhos de resposta para /app
Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA
Estratégia: dicas do lado do servidor necessárias na primeira solicitação
Pode haver casos em que você precisa de mais dicas do que o conjunto padrão na primeira solicitação. No entanto, isso provavelmente será raro, portanto, analise o raciocínio.
A primeira solicitação realmente significa a primeira solicitação de nível superior para essa origem enviada naquela sessão de navegação. O conjunto padrão de dicas inclui o nome do navegador com a versão principal, a plataforma e o indicador de dispositivos móveis. A pergunta a ser feita é: você precisa de dados estendidos no carregamento inicial da página?
Para obter dicas adicionais na primeira solicitação, há duas opções. Primeiro, é possível
usar o cabeçalho Critical-CH
. Ele tem o mesmo formato de Accept-CH
,
mas informa ao navegador que precisa repetir a solicitação imediatamente se a primeira
for enviada sem a dica crítica.
⬆️ Solicitação inicial
[With default headers]
⬇️ Cabeçalhos de resposta
Accept-CH: Sec-CH-UA-Model
Critical-CH: Sec-CH-UA-Model
🔃 O navegador tenta novamente a solicitação inicial com o cabeçalho extra
[With default headers + …]
Sec-CH-UA-Model: Pixel 5
Isso vai gerar sobrecarga na nova tentativa na primeira solicitação, mas o custo de implementação é relativamente baixo. Envie o cabeçalho extra, e o navegador fará o resto.
Para situações em que você realmente precisa de mais dicas no primeiro carregamento de página, a proposta de confiabilidade de dicas do cliente define uma maneira de especificar dicas nas configurações no nível da conexão. Isso faz uso da extensão Application-Layer Protocol Settings(ALPS) para o TLS 1.3 a fim de permitir a transmissão antecipada de dicas em conexões HTTP/2 e HTTP/3. Esse estágio ainda está em fase inicial, mas se você gerencia ativamente suas próprias configurações de TLS e conexão, esse é o momento ideal para contribuir.
Estratégia: suporte legado
Talvez você tenha um código legado ou de terceiros no seu site que dependa de
navigator.userAgent
, incluindo partes da string do user agent que serão
reduzidas. A longo prazo, é recomendável mudar para as chamadas
navigator.userAgentData
equivalentes, mas há uma solução provisória.
A retrofill do UA-CH é uma pequena
biblioteca que permite substituir navigator.userAgent
por uma nova string
criada com base nos valores navigator.userAgentData
solicitados.
Por exemplo, este código vai gerar uma string de user agent que também inclui a dica "modelo":
import { overrideUserAgentUsingClientHints } from './uach-retrofill.js';
overrideUserAgentUsingClientHints(['model'])
.then(() => { console.log(navigator.userAgent); });
A string resultante mostraria o modelo Pixel 5
, mas ainda mostraria o 92.0.0.0
reduzido,
já que a dica uaFullVersion
não foi solicitada:
Mozilla/5.0 (Linux; Android 10.0; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.0.0 Mobile Safari/537.36
Suporte adicional
Se essas estratégias não abordarem seu caso de uso, inicie uma Discussão em privacy-sandbox-dev-support repo para analisarmos o problema juntos.
Foto de Ricardo Rocha no Unsplash (links em inglês)