Canvas, Audio e WebGL: uma análise aprofundada das tecnologias de impressão digital
28/10/2025

Os sites há muito aprenderam a reconhecer os visitantes não apenas por cookies. Mesmo que você limpe seu histórico de navegação, ative o modo privado e altere IPs, seu navegador ainda pode vazar sua impressão digital. Este identificador oculto é construído a partir de muitas características técnicas do sistema. Ele segue você em cada visita.
Uma impressão digital do navegador é uma combinação de dados sobre seu dispositivo e ambiente de software. Assim como não existem dois flocos de neve idênticos, praticamente não existem dois navegadores completamente idênticos. Parâmetros individuais (por exemplo, versão do navegador ou resolução de tela) aparecem em milhares de usuários. Mas a combinação de dezenas desses detalhes cria um perfil distinto. O pior é que a impressão digital não é armazenada no seu dispositivo: ela é calculada "em tempo real" pelo site. Por esse motivo, a impressão digital não desaparece quando você limpa cookies ou usa o modo privado: cada vez que um script irá recolher os mesmos traços.
Junto com componentes simples de impressão digital como agente de usuário, fuso horário ou idioma do navegador, existem três técnicas avançadas para obtê-la: Canvas, AudioContext e WebGL. Todos os três aproveitam as capacidades gráficas e de áudio integradas do navegador para extrair informações sobre seu hardware e software. Mas como exatamente eles funcionam? Por que revelam diferenças quase imperceptíveis entre dispositivos? Vamos analisar.
Os sites há muito aprenderam a reconhecer os visitantes não apenas por cookies. Mesmo que você limpe seu histórico de navegação, ative o modo privado e altere IPs, seu navegador ainda pode vazar sua impressão digital. Este identificador oculto é construído a partir de muitas características técnicas do sistema. Ele segue você em cada visita.
Uma impressão digital do navegador é uma combinação de dados sobre seu dispositivo e ambiente de software. Assim como não existem dois flocos de neve idênticos, praticamente não existem dois navegadores completamente idênticos. Parâmetros individuais (por exemplo, versão do navegador ou resolução de tela) aparecem em milhares de usuários. Mas a combinação de dezenas desses detalhes cria um perfil distinto. O pior é que a impressão digital não é armazenada no seu dispositivo: ela é calculada "em tempo real" pelo site. Por esse motivo, a impressão digital não desaparece quando você limpa cookies ou usa o modo privado: cada vez que um script irá recolher os mesmos traços.
Junto com componentes simples de impressão digital como agente de usuário, fuso horário ou idioma do navegador, existem três técnicas avançadas para obtê-la: Canvas, AudioContext e WebGL. Todos os três aproveitam as capacidades gráficas e de áudio integradas do navegador para extrair informações sobre seu hardware e software. Mas como exatamente eles funcionam? Por que revelam diferenças quase imperceptíveis entre dispositivos? Vamos analisar.
Índice
Impressão digital do Canvas
A API de Canvas no navegador permite desenhar gráficos via JavaScript. Esta capacidade é usada discretamente para obter uma impressão digital. Um script na página cria um elemento <canvas> invisível e realiza uma série de comandos de desenho (por exemplo, renderiza texto, formas geométricas, adiciona sombra), depois lê a imagem resultante como um array de pixels. Cada dispositivo produz pequenas variações na saída final de pixels devido a diferenças no hardware e software. Um hash é então calculado a partir desses dados e usado como um identificador único do usuário.
O processo pode ser descrito passo a passo assim:
Criação do Canvas. O site visitado insere dinamicamente um elemento
<canvas>na página (geralmente fora da tela ou oculto).Desenho. O código JS renderiza gráficos de teste nesse canvas. Normalmente desenha uma string de texto em uma fonte incomum, adicionando formas coloridas, linhas e efeitos (gradientes, sombras).
Leitura dos pixels. Após desenhar, o script chama
toDataURL()(ou um método similar) para obter uma representação binária do resultado.Hashing. A string obtida (ou array de pixels) é passada por uma função de hash. O código de hash de saída é enviado para o servidor e é usado como a impressão digital.
Por exemplo, simplificando: vamos desenhar a palavra “Impressão Digital” em um Canvas e calcular um hash primitivo:
let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); canvas.width = 200; canvas.height = 50; ctx.textBaseline = "top"; ctx.font = "20px Arial"; ctx.fillStyle = "#f60"; ctx.fillText("Impressão Digital", 10, 10); let data = canvas.toDataURL(); let hash = 0; for (let i = 0; i < data.length; i++) { hash = (hash << 5) - hash + data.charCodeAt(i); hash |= 0; } console.log("Hash do Canvas:", hash);
Este código gerará um número de 32 bits (pode ser negativo devido ao overflow) que depende de como o navegador renderizou o texto. Com outro navegador (em nosso exemplo, Opera) o resultado pode diferir (embora às vezes coincida, o que é raro). Em outro PC, os resultados têm ainda mais probabilidade de diferir, embora coincidências sejam possíveis em casos extremos.
As capturas de tela abaixo mostram que mesmo no mesmo PC, mas em navegadores diferentes, o hash difere: no primeiro caso renderizamos a palavra “Impressão Digital” no Chrome, no segundo no Opera. Você pode repetir isso em seu próprio dispositivo.


Por que eles diferem? Não por causa do texto “Impressão Digital” em si: visualmente parece o mesmo ao olho humano em todos os dispositivos. As diferenças aparecem no nível de renderização: dicas de fonte, suavização de serrilhado, algoritmos de rasterização e ajustes sutis de glifos para grades de pixels são tratados de maneira diferente por diferentes sistemas operacionais e navegadores. Adicione a isso variações em GPUs e drivers, e cada dispositivo introduz pequenas distorções na imagem final. Em um pixel, a borda da letra é um pouco mais clara, em outro é mais escura, em algum lugar o glifo foi suavizado de maneira diferente. Essas diferenças microscópicas levam a hashes diferentes, mesmo que as imagens pareçam visualmente idênticas.
Os sites tentam amplificar ainda mais a variabilidade. Eles podem usar strings especialmente elaboradas que incluem todo o alfabeto e símbolos diversos para acionar muitos caminhos de código de renderização; por exemplo, uma frase que inclui quase todas as letras latinas: “Cwm fjordbank glyphs mute quiz.” Eles também podem desenhar retângulos coloridos, gradientes ou sombras sobre o texto — tudo para extrair mais detalhes únicos a nível de pixel. O resultado final da impressão digital do Canvas é a string de hash mencionada anteriormente, mas em uma forma mais complexa (por exemplo, e3d52382d0…). Este hash identifica consistentemente aquele dispositivo e, em visitas repetidas, o mesmo navegador produzirá o mesmo hash a menos que seu ambiente mude.
Assim, o Canvas dá aos sites uma ferramenta poderosa de rastreamento. Sem o consentimento do usuário, o site coleta um “render” do sistema dependente do hardware. Dispositivos com GPUs e software idênticos podem gerar impressões digitais de Canvas coincidentes, mas encontrar dois desses gêmeos é extremamente raro. Normalmente, a combinação de especificidades de GPU, fontes e software é única o suficiente para rastreamento.
Impressão digital do AudioContext
O próximo método é a impressão digital de áudio, onde a API de Web Audio se torna uma fonte de um identificador “sonoro” único. Pode parecer estranho: o site não solicita acesso ao microfone e não reproduz áudio audível. É mais sutil. O script gera e processa um sinal de áudio dentro do navegador e então extrai métricas numéricas que refletem indiretamente as características do sistema. O resultado é um identificador estável análogo ao hash do Canvas, mas baseado em áudio.
Como funciona em linhas gerais:
AudioContext. O script cria um contexto de áudio oculto (geralmente um
OfflineAudioContext) — uma “placa de som” virtual que pode processar áudio na memória sem enviá-lo para os alto-falantes.Geração de sinal. Um oscilador (
OscillatorNode) gera um tom de frequência fixa (por exemplo, 1.000 Hz para uma onda triangular). Em vez de carregar um arquivo de áudio, o oscilador sintetiza o tom programaticamente.Processamento de efeitos. Para amplificar as diferenças de hardware, o sinal é roteado através de efeitos de áudio — frequentemente um compressor (
DynamicsCompressorNode) que “espreme” a forma de onda. Ao configurar o limite, a razão, o tempo de liberação e outros parâmetros, aparecem mudanças sutis na forma de onda.Renderização e leitura. O contexto de áudio virtual renderiza rapidamente o bloco de áudio especificado na memória. Após a renderização, o script obtém um buffer de valores de amostra (uma matriz de números de ponto flutuante). Por exemplo, em 44.100 Hz e ~113 ms de duração você pode obter ~5.000 amostras.
Cálculo da impressão digital. O array de amostras é reduzido a um número compacto. Um método simples é somar os valores absolutos de todas as amostras e pegar os dígitos mais significativos. Esse número se torna a impressão digital do áudio.
Abaixo está um exemplo simples de código que você pode rodar no console do navegador para gerar uma impressão digital de áudio:
(async () => { const AC = window.OfflineAudioContext || window.webkitOfflineAudioContext; const ctx = new AC(1, 5000, 44100); const osc = ctx.createOscillator(); osc.type = 'triangle'; osc.frequency.value = 1000; const comp = ctx.createDynamicsCompressor(); comp.threshold.value = -50; comp.knee.value = 40; comp.ratio.value = 12; comp.attack.value = 0; comp.release.value = 0.25; osc.connect(comp); comp.connect(ctx.destination); osc.start(0); const rendered = await ctx.startRendering(); const samples = rendered.getChannelData(0); let acc = 0; for (let i = 0; i < samples.length; i++) acc += Math.abs(samples[i]); const demo = Math.round(acc * 1e6) / 1e6; const buf = samples.buffer.slice( samples.byteOffset, samples.byteOffset + samples.byteLength ); const hashBuf = await crypto.subtle.digest('SHA-256', buf); const hashHex = Array.from(new Uint8Array(hashBuf)) .map(b => b.toString(16).padStart(2, '0')) .join(''); console.log('Soma demo de Audio:', demo); console.log('Audio SHA-256 :', hashHex); })();
Nas capturas de tela abaixo, você pode ver que a impressão digital de áudio do mesmo PC em navegadores diferentes não difere (em nosso caso, produziu o número 953.152941). Você pode compará-los e executar o código em seu próprio PC. O resultado será idêntico, mas com sua própria impressão digital, é claro.


Assim, cada dispositivo normalmente tem seu próprio número, um hash de áudio.
Os desenvolvedores de navegadores perceberam há muito tempo o perigo desse método. A Apple foi uma das primeiras a adicionar proteção: começando com o Safari 17, no modo Privado a API de AudioContext injeta intencionalmente uma pequena aleatoriedade no som gerado. Graças a essa mudança, o mesmo Safari pode produzir diferentes hashes de áudio em diferentes sessões. A maioria dos outros navegadores ainda permite a impressão digital de áudio sem grandes obstáculos (como o exemplo acima demonstra). Combinado com dados de Canvas e WebGL, a impressão digital de áudio aumenta significativamente a capacidade de reconhecimento do dispositivo.
Impressão digital do WebGL
O HTML5 WebGL é uma API gráfica para renderizar 3D no navegador (via um <canvas> com contexto WebGL). Ele também se tornou uma ferramenta para capturar impressões digitais de dispositivos. Se a impressão digital do Canvas revela diferenças na renderização 2D, o WebGL vai mais fundo, no GPU em si. As possibilidades de identificação aqui são ainda mais amplas. A partir dos dados do WebGL você pode quase diretamente aprender o modelo do GPU e o driver, e pequenos detalhes de renderização podem até distinguir dois dispositivos com o mesmo GPU.
Um cenário típico de impressão digital de WebGL se parece com isto:
Inicialização do WebGL. O script cria um contexto WebGL (por exemplo,
canvas.getContext("webgl2")). Neste passo o script já pode obter alguns detalhes do ambiente: nome do GPU (fornecedor/renderizador), versão do driver, extensões suportadas, etc.Renderização da cena. Então um canvas oculto renderiza uma cena 3D ou primitivas especiais. Normalmente é desenhado um conjunto de formas com efeitos de shader, iluminação e texturas suficientes para exercer diferentes partes do pipeline gráfico.
Coleta de parâmetros. Após a renderização, o script lê a imagem resultante (via
gl.readPixels) e consulta um conjunto de parâmetros de WebGL: extensões suportadas, tamanhos máximos de textura, precisão de shader, stringsRENDERER/VENDOR, etc. Esses dados formam uma espécie de “instantâneo de hardware” do sistema gráfico.Geração de hash. Os números e strings coletados são combinados e transformados em hash (por exemplo, com o algoritmo SHA-256). O hash resultante se torna a impressão digital do WebGL. Ele é então enviado para o servidor e o site pode usá-lo para identificação em visitas atuais e futuras.
Aqui está um exemplo de como tal hash é gerado:
(async () => { const cv = document.createElement('canvas'); cv.width = 400; cv.height = 200; const gl = cv.getContext('webgl2', {antialias:true}) || cv.getContext('webgl', {antialias:true}); if (!gl) { console.log('WebGL недоступен'); return; } const info = {}; const dbg = gl.getExtension('WEBGL_debug_renderer_info'); if (dbg) { info.vendor = gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL); info.renderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL); } else { info.vendor = '(mascarado)'; info.renderer = '(mascarado)'; } info.version = gl.getParameter(gl.VERSION); info.glsl = gl.getParameter(gl.SHADING_LANGUAGE_VERSION); info.maxTex = gl.getParameter(gl.MAX_TEXTURE_SIZE); const vs = ` attribute vec2 p; void main(){ gl_Position = vec4(p,0.0,1.0); } `; const fs = ` precision alta float; uniform vec2 u_res; float h(vec2 v){ float s = sin(dot(v, vec2(12.9898,78.233))) * 43758.5453; return fract(s); } void main(){ vec2 uv = gl_FragCoord.xy / u_res; float r = h(uv + vec2(0.11,0.21)); float g = h(uv*1.3 + vec2(0.31,0.41)); float b = h(uv*1.7 + vec2(0.51,0.61)); gl_FragColor = vec4(pow(vec3(r,g,b)*(0.6+0.4*uv.x), vec3(1.1)), 1.0); } `; function sh(type, src){ const s = gl.createShader(type); gl.shaderSource(s, src); gl.compileShader(s); if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(s)||'erro de shader'); return s; } const pr = gl.createProgram(); gl.attachShader(pr, sh(gl.VERTEX_SHADER, vs)); gl.attachShader(pr, sh(gl.FRAGMENT_SHADER, fs)); gl.linkProgram(pr); if (!gl.getProgramParameter(pr, gl.LINK_STATUS)) throw new Error(gl.getProgramInfoLog(pr)||'erro de link'); gl.useProgram(pr); const buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buf); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 3,-1, -1,3]), gl.STATIC_DRAW); const loc = gl.getAttribLocation(pr, 'p'); gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0); const ures = gl.getUniformLocation(pr, 'u_res'); gl.uniform2f(ures, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.viewport(0,0,gl.drawingBufferWidth, gl.drawingBufferHeight); gl.clearColor(0,0,0,1); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES, 0, 3); const w = gl.drawingBufferWidth, h = gl.drawingBufferHeight; const px = new Uint8Array(w*h*4); gl.readPixels(0,0,w,h, gl.RGBA, gl.UNSIGNED_BYTE, px); const enc = new TextEncoder(); const meta = enc.encode(JSON.stringify(info)); const full = new Uint8Array(meta.length + px.length); full.set(meta, 0); full.set(px, meta.length); const hashBuf = await crypto.subtle.digest('SHA-256', full.buffer); const hex = Array.from(new Uint8Array(hashBuf)) .map(b=>b.toString(16).padStart(2,'0')).join(''); let hi = 0>>>0, lo = 0>>>0; for (let i=0;i<px.length;i+=16){ const a = px[i] | (px[i+1]<<8) | (px[i+2]<<16) | (px[i+3]<<24); hi = ((hi ^ a) + 0x9e3779b9) >>> 0; lo = ((lo ^ ((a<<7)|(a>>>25))) + 0x85ebca6b) >>> 0; hi ^= (hi<<13)>>>0; lo ^= (lo<<15)>>>0; } const sample64 = ('00000000'+hi.toString(16)).slice(-8)+('00000000'+lo.toString(16)).slice(-8); console.log('Vendedor do WebGL :', info.vendor); console.log('Renderizador WebGL:', info.renderer); console.log('Versão do WebGL :', info.version, '| GLSL:', info.glsl); console.log('MAX_TEXTURE_SIZE:', info.maxTex); console.log('SHA-256(meta+pixels):', hex); console.log('Sample64:', sample64); })();
Aqui está o que obtemos no final:

Quais diferenças o WebGL revela? Primeiro, identificadores de GPU. Por exemplo, Intel Graphics integrada e NVIDIA GeForce ou AMD Radeon discretas têm diferentes capacidades, tamanhos de VRAM e drivers, o que é refletido nos parâmetros de contexto. Segundo, variações dentro do mesmo modelo. Mesmo modelos de GPU supostamente idênticos têm pequenas diferenças individuais em desempenho e precisão de cálculos. O WebGL pode expor isso também: medir tempos de execução de shaders ou artefatos de pixels sutis na saída renderizada exporá diferenças. Finalmente, o próprio navegador importa. Diferentes motores de renderização (Blink, WebKit, Gecko) executam chamadas WebGL de maneira diferente e podem produzir resultados de renderização ligeiramente diferentes. A captura de tela abaixo mostra que quando geramos a mesma impressão digital no Opera, aparecem diferenças.

A impressão digital do WebGL é frequentemente usada em conjunto com Canvas e Audio para rastreamento em camadas, mas mesmo usada sozinha é informativa o suficiente e pode revelar muito sobre o sistema.
Como se proteger contra a impressão digital
Eliminar completamente a impressão digital do navegador é extremamente difícil, pois há muitos canais de vazamento. No entanto, uma série de medidas pode reduzir sua unicidade:
Modos e navegadores especiais. O Tor Browser impõe proteção rigorosa: todos os usuários compartilham o mesmo conjunto de características, como clones. Canvas e WebGL são desativados lá ou retornam valores médios. A desvantagem é que muitos serviços da web quebram. O Brave no modo de proteção agressiva também bloqueia medidas comuns de rastreamento. O Safari no modo Privado adiciona ruído aos dados de áudio para obscurecer a impressão digital.
Bloqueio e disfarce. Existem extensões como CanvasBlocker que impedem scripts de ler o Canvas ou disfarçam a imagem com uma aleatória. Existem também plugins para o AudioContext. No entanto, relativamente poucos usuários usam esses complementos (cerca de ~100k). Um site que vê um Canvas completamente em branco ou um hash de ruído em constante mudança suspeitará de algo. Em vez de se esconder, você pode acabar se destacando ainda mais.
Unificação do ambiente. Outra abordagem é tornar a impressão digital não única, mas genérica — por exemplo, executando o navegador dentro de uma máquina virtual ou serviço em nuvem que fornece a todos os clientes o mesmo perfil. Alguns sistemas antifraude fazem isso: usuários suspeitos são executados dentro de um “emulador de navegador” isolado onde sua impressão digital é anonimizada. Mas isso é obviamente inconveniente para navegação cotidiana.
Disfarce controlado. Uma das melhores soluções são navegadores antidetecção que permitem configuração detalhada do ambiente. Eles permitem que você decida o que o site verá de Canvas ou WebGL. Um exemplo perfeito é o Octo Browser. Ele oferece disfarce proativo: adiciona ruído ao Canvas e áudio, disfarça WebGL e outros parâmetros passiveis de impressão digital, e produz configurações que se assemelham a dispositivos reais. Navegadores antidetecção tentam imitar um navegador típico em vez de mudar tudo aleatoriamente. Um bom navegador antidetecção faz cada perfil parecer plausivelmente único sem se destacar entre milhões de outros usuários.
Se você quer permanecer verdadeiramente anônimo online, precisará de diferentes navegadores e dispositivos, manter seu software constantemente atualizado, desativar plugins desnecessários, etc., mas mesmo assim você só melhora ligeiramente suas chances de se misturar com a multidão. A alternativa melhor e mais prática é usar ferramentas profissionais como o Octo Browser. Um navegador antidetecção pode disfarçar de forma significativa e consistente sua impressão digital e ajudar a preservar a verdadeira privacidade online.
Impressão digital do Canvas
A API de Canvas no navegador permite desenhar gráficos via JavaScript. Esta capacidade é usada discretamente para obter uma impressão digital. Um script na página cria um elemento <canvas> invisível e realiza uma série de comandos de desenho (por exemplo, renderiza texto, formas geométricas, adiciona sombra), depois lê a imagem resultante como um array de pixels. Cada dispositivo produz pequenas variações na saída final de pixels devido a diferenças no hardware e software. Um hash é então calculado a partir desses dados e usado como um identificador único do usuário.
O processo pode ser descrito passo a passo assim:
Criação do Canvas. O site visitado insere dinamicamente um elemento
<canvas>na página (geralmente fora da tela ou oculto).Desenho. O código JS renderiza gráficos de teste nesse canvas. Normalmente desenha uma string de texto em uma fonte incomum, adicionando formas coloridas, linhas e efeitos (gradientes, sombras).
Leitura dos pixels. Após desenhar, o script chama
toDataURL()(ou um método similar) para obter uma representação binária do resultado.Hashing. A string obtida (ou array de pixels) é passada por uma função de hash. O código de hash de saída é enviado para o servidor e é usado como a impressão digital.
Por exemplo, simplificando: vamos desenhar a palavra “Impressão Digital” em um Canvas e calcular um hash primitivo:
let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); canvas.width = 200; canvas.height = 50; ctx.textBaseline = "top"; ctx.font = "20px Arial"; ctx.fillStyle = "#f60"; ctx.fillText("Impressão Digital", 10, 10); let data = canvas.toDataURL(); let hash = 0; for (let i = 0; i < data.length; i++) { hash = (hash << 5) - hash + data.charCodeAt(i); hash |= 0; } console.log("Hash do Canvas:", hash);
Este código gerará um número de 32 bits (pode ser negativo devido ao overflow) que depende de como o navegador renderizou o texto. Com outro navegador (em nosso exemplo, Opera) o resultado pode diferir (embora às vezes coincida, o que é raro). Em outro PC, os resultados têm ainda mais probabilidade de diferir, embora coincidências sejam possíveis em casos extremos.
As capturas de tela abaixo mostram que mesmo no mesmo PC, mas em navegadores diferentes, o hash difere: no primeiro caso renderizamos a palavra “Impressão Digital” no Chrome, no segundo no Opera. Você pode repetir isso em seu próprio dispositivo.


Por que eles diferem? Não por causa do texto “Impressão Digital” em si: visualmente parece o mesmo ao olho humano em todos os dispositivos. As diferenças aparecem no nível de renderização: dicas de fonte, suavização de serrilhado, algoritmos de rasterização e ajustes sutis de glifos para grades de pixels são tratados de maneira diferente por diferentes sistemas operacionais e navegadores. Adicione a isso variações em GPUs e drivers, e cada dispositivo introduz pequenas distorções na imagem final. Em um pixel, a borda da letra é um pouco mais clara, em outro é mais escura, em algum lugar o glifo foi suavizado de maneira diferente. Essas diferenças microscópicas levam a hashes diferentes, mesmo que as imagens pareçam visualmente idênticas.
Os sites tentam amplificar ainda mais a variabilidade. Eles podem usar strings especialmente elaboradas que incluem todo o alfabeto e símbolos diversos para acionar muitos caminhos de código de renderização; por exemplo, uma frase que inclui quase todas as letras latinas: “Cwm fjordbank glyphs mute quiz.” Eles também podem desenhar retângulos coloridos, gradientes ou sombras sobre o texto — tudo para extrair mais detalhes únicos a nível de pixel. O resultado final da impressão digital do Canvas é a string de hash mencionada anteriormente, mas em uma forma mais complexa (por exemplo, e3d52382d0…). Este hash identifica consistentemente aquele dispositivo e, em visitas repetidas, o mesmo navegador produzirá o mesmo hash a menos que seu ambiente mude.
Assim, o Canvas dá aos sites uma ferramenta poderosa de rastreamento. Sem o consentimento do usuário, o site coleta um “render” do sistema dependente do hardware. Dispositivos com GPUs e software idênticos podem gerar impressões digitais de Canvas coincidentes, mas encontrar dois desses gêmeos é extremamente raro. Normalmente, a combinação de especificidades de GPU, fontes e software é única o suficiente para rastreamento.
Impressão digital do AudioContext
O próximo método é a impressão digital de áudio, onde a API de Web Audio se torna uma fonte de um identificador “sonoro” único. Pode parecer estranho: o site não solicita acesso ao microfone e não reproduz áudio audível. É mais sutil. O script gera e processa um sinal de áudio dentro do navegador e então extrai métricas numéricas que refletem indiretamente as características do sistema. O resultado é um identificador estável análogo ao hash do Canvas, mas baseado em áudio.
Como funciona em linhas gerais:
AudioContext. O script cria um contexto de áudio oculto (geralmente um
OfflineAudioContext) — uma “placa de som” virtual que pode processar áudio na memória sem enviá-lo para os alto-falantes.Geração de sinal. Um oscilador (
OscillatorNode) gera um tom de frequência fixa (por exemplo, 1.000 Hz para uma onda triangular). Em vez de carregar um arquivo de áudio, o oscilador sintetiza o tom programaticamente.Processamento de efeitos. Para amplificar as diferenças de hardware, o sinal é roteado através de efeitos de áudio — frequentemente um compressor (
DynamicsCompressorNode) que “espreme” a forma de onda. Ao configurar o limite, a razão, o tempo de liberação e outros parâmetros, aparecem mudanças sutis na forma de onda.Renderização e leitura. O contexto de áudio virtual renderiza rapidamente o bloco de áudio especificado na memória. Após a renderização, o script obtém um buffer de valores de amostra (uma matriz de números de ponto flutuante). Por exemplo, em 44.100 Hz e ~113 ms de duração você pode obter ~5.000 amostras.
Cálculo da impressão digital. O array de amostras é reduzido a um número compacto. Um método simples é somar os valores absolutos de todas as amostras e pegar os dígitos mais significativos. Esse número se torna a impressão digital do áudio.
Abaixo está um exemplo simples de código que você pode rodar no console do navegador para gerar uma impressão digital de áudio:
(async () => { const AC = window.OfflineAudioContext || window.webkitOfflineAudioContext; const ctx = new AC(1, 5000, 44100); const osc = ctx.createOscillator(); osc.type = 'triangle'; osc.frequency.value = 1000; const comp = ctx.createDynamicsCompressor(); comp.threshold.value = -50; comp.knee.value = 40; comp.ratio.value = 12; comp.attack.value = 0; comp.release.value = 0.25; osc.connect(comp); comp.connect(ctx.destination); osc.start(0); const rendered = await ctx.startRendering(); const samples = rendered.getChannelData(0); let acc = 0; for (let i = 0; i < samples.length; i++) acc += Math.abs(samples[i]); const demo = Math.round(acc * 1e6) / 1e6; const buf = samples.buffer.slice( samples.byteOffset, samples.byteOffset + samples.byteLength ); const hashBuf = await crypto.subtle.digest('SHA-256', buf); const hashHex = Array.from(new Uint8Array(hashBuf)) .map(b => b.toString(16).padStart(2, '0')) .join(''); console.log('Soma demo de Audio:', demo); console.log('Audio SHA-256 :', hashHex); })();
Nas capturas de tela abaixo, você pode ver que a impressão digital de áudio do mesmo PC em navegadores diferentes não difere (em nosso caso, produziu o número 953.152941). Você pode compará-los e executar o código em seu próprio PC. O resultado será idêntico, mas com sua própria impressão digital, é claro.


Assim, cada dispositivo normalmente tem seu próprio número, um hash de áudio.
Os desenvolvedores de navegadores perceberam há muito tempo o perigo desse método. A Apple foi uma das primeiras a adicionar proteção: começando com o Safari 17, no modo Privado a API de AudioContext injeta intencionalmente uma pequena aleatoriedade no som gerado. Graças a essa mudança, o mesmo Safari pode produzir diferentes hashes de áudio em diferentes sessões. A maioria dos outros navegadores ainda permite a impressão digital de áudio sem grandes obstáculos (como o exemplo acima demonstra). Combinado com dados de Canvas e WebGL, a impressão digital de áudio aumenta significativamente a capacidade de reconhecimento do dispositivo.
Impressão digital do WebGL
O HTML5 WebGL é uma API gráfica para renderizar 3D no navegador (via um <canvas> com contexto WebGL). Ele também se tornou uma ferramenta para capturar impressões digitais de dispositivos. Se a impressão digital do Canvas revela diferenças na renderização 2D, o WebGL vai mais fundo, no GPU em si. As possibilidades de identificação aqui são ainda mais amplas. A partir dos dados do WebGL você pode quase diretamente aprender o modelo do GPU e o driver, e pequenos detalhes de renderização podem até distinguir dois dispositivos com o mesmo GPU.
Um cenário típico de impressão digital de WebGL se parece com isto:
Inicialização do WebGL. O script cria um contexto WebGL (por exemplo,
canvas.getContext("webgl2")). Neste passo o script já pode obter alguns detalhes do ambiente: nome do GPU (fornecedor/renderizador), versão do driver, extensões suportadas, etc.Renderização da cena. Então um canvas oculto renderiza uma cena 3D ou primitivas especiais. Normalmente é desenhado um conjunto de formas com efeitos de shader, iluminação e texturas suficientes para exercer diferentes partes do pipeline gráfico.
Coleta de parâmetros. Após a renderização, o script lê a imagem resultante (via
gl.readPixels) e consulta um conjunto de parâmetros de WebGL: extensões suportadas, tamanhos máximos de textura, precisão de shader, stringsRENDERER/VENDOR, etc. Esses dados formam uma espécie de “instantâneo de hardware” do sistema gráfico.Geração de hash. Os números e strings coletados são combinados e transformados em hash (por exemplo, com o algoritmo SHA-256). O hash resultante se torna a impressão digital do WebGL. Ele é então enviado para o servidor e o site pode usá-lo para identificação em visitas atuais e futuras.
Aqui está um exemplo de como tal hash é gerado:
(async () => { const cv = document.createElement('canvas'); cv.width = 400; cv.height = 200; const gl = cv.getContext('webgl2', {antialias:true}) || cv.getContext('webgl', {antialias:true}); if (!gl) { console.log('WebGL недоступен'); return; } const info = {}; const dbg = gl.getExtension('WEBGL_debug_renderer_info'); if (dbg) { info.vendor = gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL); info.renderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL); } else { info.vendor = '(mascarado)'; info.renderer = '(mascarado)'; } info.version = gl.getParameter(gl.VERSION); info.glsl = gl.getParameter(gl.SHADING_LANGUAGE_VERSION); info.maxTex = gl.getParameter(gl.MAX_TEXTURE_SIZE); const vs = ` attribute vec2 p; void main(){ gl_Position = vec4(p,0.0,1.0); } `; const fs = ` precision alta float; uniform vec2 u_res; float h(vec2 v){ float s = sin(dot(v, vec2(12.9898,78.233))) * 43758.5453; return fract(s); } void main(){ vec2 uv = gl_FragCoord.xy / u_res; float r = h(uv + vec2(0.11,0.21)); float g = h(uv*1.3 + vec2(0.31,0.41)); float b = h(uv*1.7 + vec2(0.51,0.61)); gl_FragColor = vec4(pow(vec3(r,g,b)*(0.6+0.4*uv.x), vec3(1.1)), 1.0); } `; function sh(type, src){ const s = gl.createShader(type); gl.shaderSource(s, src); gl.compileShader(s); if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(s)||'erro de shader'); return s; } const pr = gl.createProgram(); gl.attachShader(pr, sh(gl.VERTEX_SHADER, vs)); gl.attachShader(pr, sh(gl.FRAGMENT_SHADER, fs)); gl.linkProgram(pr); if (!gl.getProgramParameter(pr, gl.LINK_STATUS)) throw new Error(gl.getProgramInfoLog(pr)||'erro de link'); gl.useProgram(pr); const buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buf); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 3,-1, -1,3]), gl.STATIC_DRAW); const loc = gl.getAttribLocation(pr, 'p'); gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0); const ures = gl.getUniformLocation(pr, 'u_res'); gl.uniform2f(ures, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.viewport(0,0,gl.drawingBufferWidth, gl.drawingBufferHeight); gl.clearColor(0,0,0,1); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES, 0, 3); const w = gl.drawingBufferWidth, h = gl.drawingBufferHeight; const px = new Uint8Array(w*h*4); gl.readPixels(0,0,w,h, gl.RGBA, gl.UNSIGNED_BYTE, px); const enc = new TextEncoder(); const meta = enc.encode(JSON.stringify(info)); const full = new Uint8Array(meta.length + px.length); full.set(meta, 0); full.set(px, meta.length); const hashBuf = await crypto.subtle.digest('SHA-256', full.buffer); const hex = Array.from(new Uint8Array(hashBuf)) .map(b=>b.toString(16).padStart(2,'0')).join(''); let hi = 0>>>0, lo = 0>>>0; for (let i=0;i<px.length;i+=16){ const a = px[i] | (px[i+1]<<8) | (px[i+2]<<16) | (px[i+3]<<24); hi = ((hi ^ a) + 0x9e3779b9) >>> 0; lo = ((lo ^ ((a<<7)|(a>>>25))) + 0x85ebca6b) >>> 0; hi ^= (hi<<13)>>>0; lo ^= (lo<<15)>>>0; } const sample64 = ('00000000'+hi.toString(16)).slice(-8)+('00000000'+lo.toString(16)).slice(-8); console.log('Vendedor do WebGL :', info.vendor); console.log('Renderizador WebGL:', info.renderer); console.log('Versão do WebGL :', info.version, '| GLSL:', info.glsl); console.log('MAX_TEXTURE_SIZE:', info.maxTex); console.log('SHA-256(meta+pixels):', hex); console.log('Sample64:', sample64); })();
Aqui está o que obtemos no final:

Quais diferenças o WebGL revela? Primeiro, identificadores de GPU. Por exemplo, Intel Graphics integrada e NVIDIA GeForce ou AMD Radeon discretas têm diferentes capacidades, tamanhos de VRAM e drivers, o que é refletido nos parâmetros de contexto. Segundo, variações dentro do mesmo modelo. Mesmo modelos de GPU supostamente idênticos têm pequenas diferenças individuais em desempenho e precisão de cálculos. O WebGL pode expor isso também: medir tempos de execução de shaders ou artefatos de pixels sutis na saída renderizada exporá diferenças. Finalmente, o próprio navegador importa. Diferentes motores de renderização (Blink, WebKit, Gecko) executam chamadas WebGL de maneira diferente e podem produzir resultados de renderização ligeiramente diferentes. A captura de tela abaixo mostra que quando geramos a mesma impressão digital no Opera, aparecem diferenças.

A impressão digital do WebGL é frequentemente usada em conjunto com Canvas e Audio para rastreamento em camadas, mas mesmo usada sozinha é informativa o suficiente e pode revelar muito sobre o sistema.
Como se proteger contra a impressão digital
Eliminar completamente a impressão digital do navegador é extremamente difícil, pois há muitos canais de vazamento. No entanto, uma série de medidas pode reduzir sua unicidade:
Modos e navegadores especiais. O Tor Browser impõe proteção rigorosa: todos os usuários compartilham o mesmo conjunto de características, como clones. Canvas e WebGL são desativados lá ou retornam valores médios. A desvantagem é que muitos serviços da web quebram. O Brave no modo de proteção agressiva também bloqueia medidas comuns de rastreamento. O Safari no modo Privado adiciona ruído aos dados de áudio para obscurecer a impressão digital.
Bloqueio e disfarce. Existem extensões como CanvasBlocker que impedem scripts de ler o Canvas ou disfarçam a imagem com uma aleatória. Existem também plugins para o AudioContext. No entanto, relativamente poucos usuários usam esses complementos (cerca de ~100k). Um site que vê um Canvas completamente em branco ou um hash de ruído em constante mudança suspeitará de algo. Em vez de se esconder, você pode acabar se destacando ainda mais.
Unificação do ambiente. Outra abordagem é tornar a impressão digital não única, mas genérica — por exemplo, executando o navegador dentro de uma máquina virtual ou serviço em nuvem que fornece a todos os clientes o mesmo perfil. Alguns sistemas antifraude fazem isso: usuários suspeitos são executados dentro de um “emulador de navegador” isolado onde sua impressão digital é anonimizada. Mas isso é obviamente inconveniente para navegação cotidiana.
Disfarce controlado. Uma das melhores soluções são navegadores antidetecção que permitem configuração detalhada do ambiente. Eles permitem que você decida o que o site verá de Canvas ou WebGL. Um exemplo perfeito é o Octo Browser. Ele oferece disfarce proativo: adiciona ruído ao Canvas e áudio, disfarça WebGL e outros parâmetros passiveis de impressão digital, e produz configurações que se assemelham a dispositivos reais. Navegadores antidetecção tentam imitar um navegador típico em vez de mudar tudo aleatoriamente. Um bom navegador antidetecção faz cada perfil parecer plausivelmente único sem se destacar entre milhões de outros usuários.
Se você quer permanecer verdadeiramente anônimo online, precisará de diferentes navegadores e dispositivos, manter seu software constantemente atualizado, desativar plugins desnecessários, etc., mas mesmo assim você só melhora ligeiramente suas chances de se misturar com a multidão. A alternativa melhor e mais prática é usar ferramentas profissionais como o Octo Browser. Um navegador antidetecção pode disfarçar de forma significativa e consistente sua impressão digital e ajudar a preservar a verdadeira privacidade online.
Mantenha-se atualizado com as últimas notícias do Octo Browser
Ao clicar no botão, você concorda com a nossa Política de Privacidade.
Mantenha-se atualizado com as últimas notícias do Octo Browser
Ao clicar no botão, você concorda com a nossa Política de Privacidade.
Mantenha-se atualizado com as últimas notícias do Octo Browser
Ao clicar no botão, você concorda com a nossa Política de Privacidade.
Artigos relacionados
Artigos relacionados
Artigos relacionados

Junte-se ao Octo Browser agora mesmo
Ou entre em contato com a equipe de suporte no chat para tirar dúvidas a qualquer momento.

Junte-se ao Octo Browser agora mesmo
Ou entre em contato com a equipe de suporte no chat para tirar dúvidas a qualquer momento.
Junte-se ao Octo Browser agora mesmo
Ou entre em contato com a equipe de suporte no chat para tirar dúvidas a qualquer momento.


