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 User-Agent é uma superfície de impressão digital passiva importante nos navegadores, além de ser difícil de processar. No entanto, há vários motivos válidos para coletar e processar dados de user agent. Portanto, o que é necessário é um caminho para uma solução melhor. As dicas do cliente do user-agent oferecem uma maneira explícita de declarar sua necessidade de dados de user-agent e métodos para retornar os dados em um formato fácil de usar.
Neste artigo, você vai aprender a auditar seu acesso aos dados do user agent e migrar o uso da string do user agent para as dicas de cliente do user agent.
Auditoria da coleta e do uso de dados de 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
. Também verifique se o código front-end
usa recursos descontinuados, como navigator.platform
e
navigator.appVersion
.
De um ponto de vista funcional, pense em qualquer lugar do código em que você está gravando ou processando:
- Nome ou versão do navegador
- Nome ou versão do sistema operacional
- Marca ou modelo do dispositivo
- Tipo, arquitetura ou bitness da CPU (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 às dicas de cliente 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/significativaSec-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 forma 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 nome do navegador, versão principal ou sistema operacional, o código continuará funcionando, mas é provável que você receba avisos de descontinuação.
Embora seja possível e recomendável migrar para as dicas de cliente do user agent, você pode ter restrições de código legado ou de recursos 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 a analisar a
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 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
});
Você também pode usar essa estratégia se quiser mudar do processamento do lado do servidor para o do lado 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, poderá
especificar as dicas de cliente desejadas como um conjunto estático nas respostas. Essa é uma
abordagem relativamente simples, já que geralmente você só precisa configurá-la em um
local. Por exemplo, pode estar na configuração do servidor da Web, se você já
adicionou cabeçalhos, na configuração de hospedagem ou na configuração de nível superior do
framework ou da plataforma que você usa para o site.
Considere essa estratégia se você estiver transformando ou personalizando as respostas fornecidas com base nos dados do user-agent.
Navegadores ou outros clientes podem fornecer dicas padrão diferentes. Por isso, é uma boa prática especificar tudo o que você precisa, mesmo que 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 servidor, primeiro verifique se o cabeçalho
Sec-CH-UA
desejado foi enviado e, em seguida, use a análise do cabeçalho
User-Agent
se ele não estiver disponível.
Estratégia: delegar dicas para solicitações entre origens
Se você estiver solicitando subrecursos de origem cruzada ou entre sites que exigem que as dicas de cliente do user agent sejam enviadas 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.
O https://blog.site
pode solicitar a sugestão Sec-CH-UA-Model
, mas precisa
delegar isso explicitamente para https://cdn.site
usando o cabeçalho
Permissions-Policy
. A lista de dicas controladas por políticas está disponível no rascunho da infraestrutura
de Client Hints.
⬇️ 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 para subrecursos em cdn.site
inclui a sugestão delegada
Sec-CH-UA-Model: "Pixel 5"
É possível especificar várias dicas para várias origens, e não apenas do intervalo ch-ua
:
⬇️ Resposta de blog.site
delegando várias dicas para 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 para iframes
Os iframes entre origens funcionam de maneira semelhante aos recursos entre origens, mas você
especifica as dicas que gostaria de delegar no atributo allow
.
⬇️ Resposta de blog.site
Accept-CH: Sec-CH-UA-Model
↪️ HTML para 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 por rota, pode ser viável.
O importante a lembrar aqui é que cada instância do cabeçalho Accept-CH
vai substituir o conjunto atual. Portanto, se você estiver definindo o cabeçalho
de forma dinâmica, cada página precisará solicitar o conjunto completo de dicas necessárias.
Por exemplo, você pode ter uma seção no seu site em que quer fornecer
ícones e controles que correspondam ao sistema operacional do usuário. Para isso, talvez seja necessário
usar Sec-CH-UA-Platform-Version
para fornecer subrecursos
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ê vai precisar de mais do que o conjunto padrão de dicas na primeira solicitação. No entanto, isso é raro, então verifique se você analisou o raciocínio.
A primeira solicitação significa a primeira solicitação de nível superior para essa origem enviada nessa 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 dispositivo móvel. A pergunta a ser feita aqui é: você precisa de dados estendidos no carregamento inicial da página?
Para mais dicas sobre a primeira solicitação, há duas opções. Primeiro, você pode
usar o cabeçalho Critical-CH
. Ele tem o mesmo formato de Accept-CH
,
mas informa ao navegador que ele precisa tentar a solicitação imediatamente se a primeira
foi 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 da 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 dicas adicionais na primeira carga da página, a proposta de confiabilidade de dicas do cliente está definindo uma rota para especificar dicas nas configurações de nível de conexão. Isso usa a extensão Application-Layer Protocol Settings(ALPS) para TLS 1.3 para permitir essa 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, planeje migrar para as chamadas
navigator.userAgentData
equivalentes, mas há uma solução provisória.
O 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
Mais suporte
Se essas estratégias não atenderem ao seu caso de uso, inicie uma discussão no repo privacy-sandbox-dev-support e podemos analisar o problema juntos.
Foto de Ricardo Rocha no Unsplash (links em inglês)