Fingerprinting de canvas além do básico: por que dois Chromes idênticos renderizam pixels diferentes
Dois dispositivos com o mesmo Chrome, SO e GPU ainda renderizam pixels de canvas diferentes. Por que o pipeline de renderização não é determinístico, por que a injeção de ruído sai pela culatra e onde o canvas se encaixa hoje.
O fingerprinting de canvas está em uso em produção desde 2012. A ideia é direta: pedir ao navegador que renderize conteúdo 2D, ler de volta os pixels e calcular um hash deles. Dispositivos diferentes produzem pixels ligeiramente diferentes para as mesmas instruções, e essas diferenças são estáveis o bastante para identificar um dispositivo entre sessões.
Até aí, nada de novo. O que é menos compreendido é por que a técnica funciona — por que configurações de software idênticas em hardware idêntico ainda produzem saídas de pixel diferentes. A resposta está na interseção entre drivers de GPU, renderização de fontes e aritmética de ponto flutuante.
O pipeline de renderização não é determinístico
Quando o JavaScript chama context.fillText("Cwm fjord bank glyphs vext quiz", 4, 45), o Chrome não renderiza os pixels por conta própria. Ele gera instruções para o Skia — a biblioteca de gráficos 2D — que, por sua vez, emite comandos de desenho para um backend acelerado por GPU (geralmente ANGLE no Windows, Metal no macOS ou fallback por software em contêineres).
Em cada etapa, pequenas diferenças de implementação se acumulam:
-
O subsistema de fontes do Skia seleciona uma família de fontes. Se a Arial não estiver instalada, ele recorre a um fallback — e o fallback varia conforme as fontes instaladas no sistema.
-
A fonte selecionada é renderizada no tamanho solicitado usando FreeType (no Linux), DirectWrite (no Windows) ou Core Text (no macOS). Cada biblioteca tem algoritmos de hinting diferentes.
-
O posicionamento de subpixel é aplicado. É aqui que fontes idênticas começam a produzir pixels diferentes — o algoritmo arredonda as posições para deslocamentos fracionários de pixel, e as regras de arredondamento diferem entre plataformas.
-
O texto rasterizado é composto sobre o canvas. A mesclagem é feita por shaders de GPU em sistemas com aceleração de hardware, e por código de CPU no modo de fallback.
Cada uma dessas etapas pode introduzir diferenças de um ou dois valores de pixel. Individualmente invisíveis. Coletivamente únicas.
As versões do driver de GPU dominam o fingerprint
Duas máquinas Windows 11 com chips Intel UHD Graphics 620 podem produzir saídas de canvas diferentes se seus drivers de GPU diferirem. A Intel lança atualizações de driver várias vezes por ano, e cada atualização pode alterar a filtragem de subpixel, a correção de gama e o anti-aliasing de texto.
Isso significa que a estabilidade do fingerprint de canvas é limitada pela frequência de atualização dos drivers. Um usuário que atualiza seu driver gráfico — muitas vezes silenciosamente, via Windows Update — verá seu fingerprint de canvas mudar.
Os sistemas de detecção lidam com isso tratando o fingerprint de canvas como um entre muitos sinais, não como um identificador autônomo. Quando ele muda, mas os outros sinais permanecem estáveis (impressão digital de TLS, renderer de WebGL, fuso horário, fontes instaladas), o visitante continua sendo reconhecido.
A renderização de emoji é uma mina de ouro
O elemento mais identificador de um fingerprint de canvas muitas vezes não é texto nem formas, mas emoji. A renderização de emoji depende da fonte de emoji que acompanha o SO — Segoe UI Emoji no Windows, Apple Color Emoji no macOS, Noto Color Emoji no Android.
Mesmo dentro de um único SO, a renderização de emoji muda entre versões. A renderização de um emoji de arco-íris no Windows 10 difere da do Windows 11. O rosto sorridente do iOS 16 tem um anti-aliasing diferente do iOS 17.
Os scripts modernos de fingerprinting de canvas renderizam especificamente sequências de emoji que incluem adições recentes ao Unicode. Um visitante que afirma rodar o Safari em um iPhone, mas não consegue renderizar um emoji adicionado no iOS 17, está rodando um iOS mais antigo — ou mentindo sobre a plataforma.
Frameworks de automação produzem fingerprints característicos
O Chrome headless, rodando em um contêiner Docker sem GPU, usa o SwiftShader para renderizar. O SwiftShader produz saídas de canvas internamente consistentes, mas distintas de qualquer Chrome com aceleração de hardware.
A assinatura é reconhecível: anti-aliasing incomumente limpo, valores de cor específicos em regiões de gradiente e bordas de texto que não correspondem a nenhum driver de GPU conhecido. Um fingerprint de canvas que corresponde ao SwiftShader em um Chrome 124 em contêiner Linux é quase certamente automação — nenhum usuário real roda um navegador dessa forma.
O puppeteer-extra-stealth tenta falsificar a saída do canvas interceptando toDataURL() e retornando dados modificados. Mas a modificação frequentemente introduz artefatos próprios — padrões de ruído que se repetem entre sessões, o que paradoxalmente torna o esforço anti-fingerprinting mais detectável do que não fazer nada.
Por que a injeção de ruído não funciona bem
Navegadores focados em privacidade, como o Brave, injetam ruído na saída do canvas para impedir o rastreamento. A ideia é adicionar pequenas variações aleatórias aos valores de pixel para que o mesmo dispositivo produza fingerprints diferentes a cada sessão.
Na prática, a injeção de ruído tem três problemas:
1. O próprio ruído é um fingerprint. Um visitante cuja saída de canvas muda a cada carregamento, mas cujos outros sinais permanecem idênticos, é reconhecível como um navegador que injeta ruído. Isso, por si só, é identificador.
2. O algoritmo de ruído é estável. A implementação do Brave produz padrões de ruído específicos que não correspondem à variância natural da renderização por GPU. Os sistemas de detecção conseguem identificar saídas de canvas que parecem ter ruído injetado versus as que parecem naturais.
3. Sistemas sofisticados combinam amostras. Múltiplas renderizações na mesma página, ou entre sessões, podem ser promediadas. Se o ruído for pequeno, a média converge para o fingerprint determinístico subjacente.
O que o fingerprinting de canvas captura
Além da saída visual óbvia, o fingerprinting de canvas pode extrair vários atributos do dispositivo como efeitos colaterais:
Tempo de renderização — quanto tempo o canvas leva para renderizar revela a capacidade da GPU. Um desktop 4K com GPU dedicada renderiza mais rápido que um laptop intermediário.
Métricas de texto — measureText() retorna larguras exatas em pixels que variam conforme a renderização de fontes. A largura do texto pode ser usada como fingerprint mesmo sem renderizar.
Suporte a operações de composição — alguns navegadores ou configurações de GPU suportam modos de composição estendidos. Testar o suporte revela os limites de capacidade.
Efeitos de filtro — filtros no estilo CSS aplicados ao canvas produzem saídas diferentes entre GPUs, especialmente os filtros de desfoque e drop-shadow.
Onde o fingerprinting de canvas se encaixa em um stack de detecção
Sozinho, o fingerprinting de canvas não é um identificador robusto. Drivers mudam. Usuários trocam de navegador. A injeção de ruído é comum em públicos focados em privacidade.
Sua verdadeira força é como contraprova. Quando uma sessão afirma ser de um usuário recorrente com base em cookies ou login de conta, o fingerprint de canvas atua como um segundo sinal — a correspondência com o fingerprint histórico confirma a afirmação; a divergência sinaliza roubo de conta ou sequestro de sessão.
Para a detecção de bots, o fingerprinting de canvas se destaca em flagrar automação em contêiner. Usuários reais têm GPUs reais. GPUs reais produzem assinaturas de renderização reconhecíveis. Qualquer coisa que renderize como o SwiftShader, ou como um canvas mal falsificado, cai no balde de quase certamente bot.
A técnica de 2012 ainda funciona em 2026 pela mesma razão: a renderização é determinística por ambiente, mas quase impossível de falsificar por completo. Toda tentativa de se esconder deixa rastros da própria tentativa.