AlterAntiX
Voltar ao blog
Técnico11 min de leitura

User Agent Spoofing: Por Que Trocar a String Não Engana Mais Ninguém

Trocar o user agent sozinho não engana ninguém desde muito antes de você começar a operar multiconta. Este artigo mostra as 4 checagens cruzadas que denunciam um user agent falso e por que o TLS trai a string antes de qualquer JavaScript rodar.

Instala uma extensão, escolhe outro navegador num menu, e o site passa a achar que você está num Mac. Isso foi verdade por uns dez anos e deixou de ser há bastante tempo. Aqui estão as quatro checagens cruzadas que denunciam um user agent trocado, e por que a mais importante delas já respondeu antes de o seu primeiro script rodar.

A técnica que todo tutorial antigo ainda ensina

O user agent é um cabeçalho único que o navegador anexa a toda requisição, descrevendo a si mesmo: navegador, versão, motor, sistema operacional. É uma autodeclaração, e ninguém nunca verificou nada ali — motivo exato de ter virado a primeira coisa que as pessoas aprenderam a trocar. Por anos trocar funcionou, porque os sites não tinham com o que comparar.

Duas coisas encerraram essa era. A primeira é que os próprios navegadores reduziram o quanto a string diz. O Chrome congelou boa parte do detalhe faz tempo; a versão do sistema operacional virou genérica, os números de versão menor viraram zeros, e a string que carregava uma descrição precisa da máquina passou a carregar uma categoria grosseira. A segunda é que tudo aquilo que a string sustentava mudou de lugar, para pontos onde um cabeçalho não chega.

A situação moderna, então, não é que o user agent seja checado com mais rigor. É que o user agent virou uma afirmação que outros quatro sistemas conseguem verificar por conta própria, e ninguém perde tempo checando uma afirmação que dá para medir.

Trocar o user agent ainda engana detectores?

Sozinho, não, e o motivo é estrutural em vez de ser questão de qualidade da ferramenta. Trocar o user agent muda uma afirmação. Não muda o que a máquina faz. Toda checagem abaixo lê um comportamento em vez de uma afirmação, e é por isso que elas não se satisfazem com a edição de uma string — e por isso se contradizem no instante em que a string se move e o comportamento não.

Vale dizer antes da crítica: trocar o user agent é uma ferramenta perfeitamente boa para o trabalho que ela foi feita. Testar como uma página renderiza no celular, forçar um site a servir o layout móvel, conferir se um ramo antigo de navegador ainda funciona — uma extensão de troca faz tudo isso bem, e nada disso envolve convencer alguém de coisa nenhuma. O problema começa quando uma técnica feita para teste é vendida como separação de identidade. São objetivos diferentes, e só um deles é contestado pelo outro lado.

O que vem a seguir não é um ranking de gravidade. São quatro superfícies independentes, e um sistema de risco sério lê as quatro e compara. Uma contradição é anomalia. Duas são conclusão.

Checagem 1 — o resto do objeto navigator

O user agent é uma propriedade entre dezenas que descrevem a mesma máquina, e as outras são lidas pelo JavaScript em vez de virem num cabeçalho. A comparação primeira e mais barata é navigator.platform contra o sistema operacional citado na string: um user agent dizendo Windows ao lado de um platform reportando Mac é uma contradição que custa ao detector uma linha de código.

Os valores vizinhos importam pelo mesmo motivo. navigator.hardwareConcurrency reporta núcleos de CPU, deviceMemory reporta memória dentro de um conjunto pequeno de valores permitidos, e largura, altura e pixel ratio descrevem um monitor. Nada disso se move quando o user agent se move. Um perfil declarando iPhone enquanto reporta uma tela de desktop de dois mil pixels, dezesseis núcleos e trinta e dois gigabytes de memória descreveu um aparelho que não existe.

A armadilha aqui é que corrigir parece fácil e não é. Todo valor que você define precisa continuar dentro da faixa que hardware real reporta. Memória só aparece em valores específicos que a API pode expor; tela tem que ser um tamanho que se fabrica; contagem de núcleos tem limites plausíveis. Um perfil com valores escolhidos à vontade é mais identificável que um que nunca mudou nada, porque aterrissa numa região do espaço onde máquina real nenhuma mora.

Checagem 2 — Client Hints, a parte que a string não cobre

Essa é a checagem de que a maioria dos tutoriais nunca ouviu falar, e é a que pega spoofing de extensão quase sempre.

Enquanto a string do user agent era reduzida, o Chromium introduziu um substituto pensado para entregar a mesma informação de forma estruturada e negociável: os User-Agent Client Hints. Três deles são de baixa entropia e saem em toda requisição sem ninguém pedir — marca e versão significativa, um indicador de mobile e a plataforma. O resto é de alta entropia: versão da plataforma, arquitetura, bitness, modelo do aparelho, lista completa de versões. Esses só saem quando o servidor pede explicitamente com um cabeçalho Accept-CH na resposta, ou quando a página os lê por getHighEntropyValues no JavaScript.

A consequência é direta. Uma ferramenta que reescreve o cabeçalho do user agent e para por aí deixa uma segunda descrição paralela da máquina saindo em cada requisição, ainda descrevendo a máquina verdadeira. O site não precisa ser esperto; ele lê as duas e percebe que discordam.

A armadilha de escopo que quase ninguém cita
Mesmo uma ferramenta que corrige os Client Hints pelo JavaScript costuma corrigir só na janela da página. Iframes, web workers, service workers e os cabeçalhos anexados a requisições de fundo são contextos de execução separados, e um patch aplicado a uma janela não alcança nenhum deles. Um site consegue ler o valor falsificado na página e o valor real vindo de um worker, na mesma sessão. Resolver isso de verdade exige sobrescrever no nível do navegador, não dentro da página.

Checagem 3 — a camada de renderização

A terceira superfície não pergunta ao navegador o que ele é. Pede que ele desenhe e depois lê o resultado. Saída de canvas, saída de imagem do WebGL, as strings não mascaradas de vendor e renderer, e a lista de fontes que o sistema consegue resolver descrevem a máquina de baixo em vez da máquina alegada.

A string do renderer é a mais direta delas. Uma máquina Windows real reporta uma string ANGLE apoiada em Direct3D, uma máquina Linux reporta uma string OpenGL, um Mac reporta uma string da Apple citando Metal. Esse valor descreve a pilha gráfica, e a pilha gráfica pertence ao sistema operacional. Um user agent dizendo Windows sobre um renderer que descreve outra plataforma não é um descasamento sutil, e não precisa de análise estatística para ser notado.

Fontes funcionam do mesmo jeito, pelo lado inverso. Todo sistema operacional traz um conjunto característico, e uma página testa quais resolvem medindo a largura de um texto renderizado. Um perfil alegando macOS numa máquina que não resolve nenhuma fonte de sistema da Apple respondeu à pergunta por omissão. Nosso artigo sobre canvas e WebGL percorre essa camada inteira, inclusive por que ruído ingênuo piora tudo.

Checagem 4 — TLS, que responde antes de o JavaScript existir

A quarta checagem acontece antes da página. Toda conexão HTTPS abre com um handshake TLS, e o primeiro pacote — o ClientHello — carrega as suítes de cifra que o cliente suporta e a ordem delas, as extensões que ele oferece e a ordem delas, as curvas elípticas que aceita e o protocolo de aplicação que prefere. Essa combinação é característica de um navegador específico construído sobre uma versão específica de motor. JA3 e JA4 são as formas padronizadas de transformar isso num fingerprint.

Duas propriedades fazem dessa a camada mais difícil de falsificar. Ela é montada pela biblioteca TLS do runtime, então JavaScript nenhum a reescreve. E ela sai antes do primeiro byte de HTML, o que significa que o servidor já a tem quando o seu cabeçalho de user agent chega — a contradição está disponível no momento em que a requisição aterrissa, não depois de alguma análise.

É aqui que o artigo inteiro converge. Você pode passar na checagem do navigator, na de Client Hints e na de renderização, e ainda ser contrariado por um handshake dizendo que quem enviou isso foi outro navegador. Pior: uma correção parcial cria o próprio problema — um perfil cujo user agent diz uma versão de Chrome enquanto o TLS imita outra está descrevendo um navegador que nunca foi lançado. Cobrimos essa camada em profundidade à parte — este artigo está uma camada acima dela, e as duas só funcionam juntas.

O que precisa mudar junto com o user agent

Lidas como checklist, as quatro superfícies produzem uma lista curta de coisas que precisam se mover como conjunto. O que ficar para trás vira a contradição.

SinalO que a troca de UA sozinha fazO que precisa acontecer de fato
Cabeçalho user agentMudaMuda, e fica preso a uma versão que o resto da pilha consegue sustentar
Client Hints (baixa entropia, toda requisição)Normalmente intocadoReescrito no nível do navegador para todo contexto concordar, não só a janela da página
navigator.platform, núcleos, memória, telaIntocadoDefinido em valores coerentes com o sistema declarado e dentro de faixas de hardware real
Vendor e renderer do WebGLIntocadoUma pilha gráfica que pertence ao sistema operacional declarado
Lista de fontesIntocadaUm conjunto de fontes característico do sistema declarado
ClientHello do TLS (JA3 / JA4)Intocado — JavaScript não alcançaUm handshake casado com a versão exata de navegador que o user agent alega

Ler essa tabela de cima a baixo explica por que extensão não resolve isso e por que o problema é do navegador, não de uma ferramenta que vive dentro da página. As linhas um e dois são alcançáveis de dentro de uma página, com as limitações de escopo já descritas. As linhas três a cinco exigem controle sobre o runtime. A linha seis exige controle sobre a pilha de rede, que fica fora do navegador.

Existe também uma regra prática escondida na tabela, e ela inverte o instinto comum. O user agent mais seguro de declarar não é o mais novo nem o mais raro — é aquele que todas as outras linhas conseguem sustentar. Um perfil está melhor alegando uma versão de Chrome que a camada TLS reproduz com exatidão e que a pilha de renderização pode plausivelmente ter, mesmo que essa versão esteja algumas atrás, do que alegando o lançamento mais recente e se contradizendo duas vezes para chegar lá. Consistência vale mais que atualidade aqui, e isso é o oposto do que a maioria das telas de configuração incentiva.

Como o AlterAntiX mantém tudo coerente

O AlterAntiX trata isso como um objeto só em vez de seis configurações. Três partes valem descrição concreta, porque são afirmações verificáveis em vez de adjetivos.

Os Client Hints são definidos no nível do navegador, não injetados na página. Os metadados de user agent são aplicados pelo protocolo de controle do navegador, que os propaga para todo contexto de execução — página, iframes, workers, service workers e cabeçalhos de requisição de saída — em vez de só a janela que um script de página enxerga. É isso que fecha a armadilha de escopo descrita antes.

Um validador de coerência roda contra o perfil e aponta as contradições. Ele compara o user agent com a plataforma, confere o marcador de mobile contra a classe de aparelho declarada, verifica se vendor e renderer do WebGL são da mesma família, confirma que uma GPU Apple não está sendo alegada num sistema que não é Apple, checa se o primeiro idioma declarado bate com o locale, e valida tela, pixel ratio, contagem de núcleos e memória contra faixas plausíveis. A nota é fórmula aberta: o perfil começa em 100 e perde 10 pontos por contradição encontrada, mais a penalidade de proxy — 30 se o proxy está morto, 20 se sumiu, 10 se nunca foi testado, 5 se não há proxy nenhum.

O seletor de versão de Chrome diz onde a cobertura de TLS é exata. A impersonação de TLS embutida traz um conjunto finito de presets, e escolher uma versão de Chrome sem correspondência exata faz o handshake imitar uma versão vizinha enquanto a string diz outra coisa. Em vez de esconder isso, o seletor marca cada opção como correspondência exata, próxima ou sem correspondência próxima, e o padrão do perfil fica numa versão em que as duas camadas concordam. Ser avisado de qual escolha é segura é mais útil que receber todas as versões como se fossem equivalentes.

Tudo isso você confere por fora do produto. Abra o verificador de fingerprint no que você usa hoje e compare, na mesma tela, o user agent declarado contra a plataforma, os Client Hints, o renderer do WebGL e o fingerprint de TLS. Se dois deles discordarem, você achou a contradição antes de uma plataforma achar. O AlterAntiX é download gratuito para desktop em Windows e Linux, se você quiser comparar um perfil coerente com a sua configuração atual.

Leve isto daqui
  • O user agent é uma afirmação. Toda checagem que importa lê comportamento, então trocar a string só cria contradição.
  • Client Hints levam uma descrição paralela da máquina em toda requisição — três deles sem o servidor sequer pedir.
  • Patch aplicado só na janela da página deixa iframes, workers e requisições de fundo reportando a verdade.
  • A camada de renderização responde desenhando: renderer de WebGL e lista de fontes descrevem o sistema real.
  • O TLS responde antes de todo mundo, antes de qualquer JavaScript, e o JavaScript não alcança essa camada.
  • O objetivo é coerência, não ocultação: tudo precisa descrever uma máquina plausível só, inclusive a versão do navegador.

Perguntas frequentes

Extensão que troca o user agent serve para alguma coisa?

Serve para testar layout responsivo e para forçar a versão móvel de um site. Não serve para separar identidade de conta. A extensão troca a string e, dependendo da implementação, os Client Hints — e não toca em nada da camada de renderização nem na camada de rede, que são justamente as que denunciam.

Qual é o sinal mais barato que denuncia um user agent falso?

A comparação entre o sistema declarado na string e o que a pilha gráfica reporta no WebGL. Uma string de Windows com um renderer que descreve pilha de outro sistema é contradição direta, custa uma comparação e não tem explicação inocente.

Os Client Hints são enviados sempre?

Três deles sim: marca e versão significativa, indicador de mobile e plataforma vão em toda requisição em navegadores Chromium. Os demais, como versão da plataforma, arquitetura, modelo e lista completa de versões, são de alta entropia e só saem quando o servidor pede por Accept-CH ou quando a página consulta getHighEntropyValues no JavaScript.

Por que o TLS entrega a string antes do JavaScript?

Porque o handshake TLS acontece antes de a primeira linha de HTML chegar. O ClientHello carrega a lista de cifras, a ordem das extensões e o ALPN, e essa combinação é característica de cada navegador e versão. Quando o JA3 ou JA4 diz uma coisa e o user agent diz outra, o servidor já tinha as duas respostas antes de qualquer script rodar.

Trocar o user agent para uma versão mais nova é mais seguro?

Só se todo o resto acompanhar. Uma versão de Chrome sem preset de TLS correspondente faz a camada de rede imitar uma versão vizinha, e aí a string e o handshake divergem. Prefira as versões para as quais a sua ferramenta tem cobertura exata de TLS em vez da mais recente que existir.

O que o AlterAntiX faz de diferente aqui?

Trata user agent, plataforma, Client Hints, WebGL, tela, idioma e preset de TLS como um conjunto que precisa concordar, com um validador de coerência que aponta a contradição antes de o perfil abrir, e com o seletor de versão de Chrome sinalizando quais versões têm correspondência exata de TLS.

Fingerprint e TLS alinhados, de verdade

O AlterAntiX casa o fingerprint do navegador com o TLS na mesma versão de Chrome. Baixe e teste você mesmo.

Baixar o AlterAntiX