- O Safari 17 adiciona ruído aleatório a cada amostra da Audio API no modo privado para embaralhar a impressão digital de áudio, mas a FingerprintJS respondeu com um novo algoritmo de fingerprint para reduzir esse efeito
- O método anterior usava a soma de 500 amostras de áudio como identificador, então a faixa de ruído do Safari ficou maior que as diferenças entre navegadores, fazendo-o perder estabilidade
- O novo método cria em grande quantidade cópias ruidosas da mesma amostra de áudio e reduz a oscilação dos valores com
(min+max)/2e arredondamento por algarismos significativos - Ao conectar
OscillatorNodesquare,DynamicsCompressorNodeeBiquadFilterNode, eles ampliaram as diferenças entre navegadores e elevaram a menor diferença da amostra 3396 entre os navegadores selecionados para0.0014% - O novo algoritmo substituiu a impressão digital de áudio anterior a partir do FingerprintJS 4.2.0; o tempo de cálculo aumenta de 1,5 a 2 vezes, mas ainda termina rapidamente mesmo em dispositivos de baixo desempenho
Como o Safari 17 embaralha a impressão digital de áudio
- A impressão digital de áudio renderiza um sinal de áudio com a Audio API e o OfflineAudioContext, depois soma as amostras para gerar um único número identificador
- Esse identificador tem estabilidade, pois não muda mesmo após apagar cookies ou alternar para o modo anônimo, mas sua unicidade não é alta porque muitos usuários podem compartilhar o mesmo valor
- A proteção avançada contra fingerprint do Safari 17 fica ativada por padrão no modo privado e desativada no modo normal, valendo tanto para desktop quanto para mobile
- A proteção também afeta a Screen API e a Canvas API, mas aqui o foco é apenas a Audio API
- Quando a proteção está ativada, o Safari multiplica cada amostra de áudio por um ruído aleatório individual
- A amostra com ruído fica entre
sample*(1-magnitude)esample*(1+magnitude) - A distribuição é uniforme
- Como o desenvolvimento do Safari continua, os detalhes de implementação podem mudar com o tempo
- A amostra com ruído fica entre
Pontos da Audio API onde o ruído é aplicado
- O Safari aplica ruído em várias interfaces pelas quais é possível ler o sinal de áudio
- AudioWorkletNode: magnitude
0.001 - AudioBuffer::getChannelData: magnitude
0.001 - AudioBuffer::copyFromChannel: magnitude
0.001 - RealtimeAnalyser::getFloatFrequencyData: magnitude
0.25
- AudioWorkletNode: magnitude
- Como o ruído muda a cada aplicação, a impressão digital de áudio no modo privado do Safari 17 muda a cada cálculo
- No Safari 17 de um M1 MacBook Air, a fingerprint varia entre
124.03516e124.04545, uma diferença de cerca de0.008% - Entre as diferenças da impressão digital de áudio anterior por navegador, o menor valor era
0.0000023%, muito menor que a faixa de ruído do Safari - Para eliminar o ruído seria preciso arredondar para algo como uma casa decimal, mas com menos de 6 dígitos restantes fica difícil distinguir alguns navegadores, reduzindo a unicidade
As 3 etapas do novo algoritmo
- O novo algoritmo de impressão digital de áudio da FingerprintJS passa por três etapas para reduzir o ruído adicionado pelo Safari
- Reduz a variância do ruído
- Aumenta a distância entre os números identificadores dos navegadores
- Remove o ruído restante com arredondamento
- Como a fingerprint de áudio anterior era a soma de 500 amostras de áudio, quando se adiciona ruído de distribuição uniforme a cada amostra, o ruído total da fingerprint se aproxima de uma distribuição normal
- A média de uma distribuição normal precisa ser estimada pela média de muitas amostras, mas a média de uma distribuição uniforme pode ser estimada com precisão a partir de menos amostras usando
(min+max)/2 - No código experimental, sob as mesmas condições de precisão, a distribuição normal exigiu
524,288amostras, enquanto a uniforme precisou de apenas4,096 - Em vez da fingerprint por soma, o novo método passou a coletar apenas uma única amostra de áudio, para lidar com ruído de distribuição uniforme
- Por causa dessa mudança, a nova fingerprint não é compatível com a anterior, e é necessária uma abordagem separada para migrar sem perder os identificadores dos visitantes
Criando cópias ruidosas da mesma amostra de áudio
- Chamar
getChannelDatavárias vezes em uma instância deAudioBuffernão funciona- O ruído é aplicado uma vez por instância de
AudioBuffer getChannelDatada mesma instância retorna o mesmo sinal
- O ruído é aplicado uma vez por instância de
- É possível criar muitas instâncias de
AudioBufferrepetindo todo o processo de geração do sinal de áudio, mas isso é lento demais para calcular fingerprint6,000amostras de ruído levaram no mínimo 7 segundos em um M1 MacBook- Com
60,000, o Safari não conseguiu concluir a tarefa
- Um método melhor é criar uma instância de
AudioBufferque repita o mesmo sinal de áudio- O primeiro sinal de áudio é renderizado, mas
getChannelDatanão é chamado - Em seguida, cria-se um segundo OfflineAudioContext mais longo, usando o sinal original como AudioBufferSourceNode
loop,loopStarteloopEndrepetem parte do sinal original- Como o Safari adiciona ruído após a repetição, obtêm-se cópias da mesma amostra de áudio com ruídos diferentes
- O primeiro sinal de áudio é renderizado, mas
- Esse método permite criar a quantidade necessária de cópias com ruído com apenas 2 renderizações de áudio
- O ruído não desaparece completamente, mas a variância fica menor que na amostra de áudio original
8,192cópias: faixa de0.000387%em 100 execuções,2.6msem um M1 MacBook65,536cópias:0.0000123%,4.1ms262,144cópias:0%,7.5ms
Aumentando a diferença entre amostras de áudio dos navegadores
- Reduzir o número de cópias melhora o desempenho, mas aumenta a variância do resultado; por isso, o sinal base foi alterado para ampliar as diferenças entre navegadores
- Após testar vários nós de áudio embutidos, a cadeia de geração de sinal que mais aumentou as diferenças entre amostras de navegadores foi a seguinte
- OscillatorNode square
- DynamicsCompressorNode
- BiquadFilterNode do tipo
allpass
- A amostra de número 3396 do sinal de áudio foi a que apresentou a maior diferença entre navegadores, valor encontrado comparando todas as amostras de vários navegadores
- Na amostra de navegadores selecionada, a menor diferença dessa nova amostra foi
0.0014%- Maior que a menor diferença da fingerprint anterior,
0.0000023% - Isso permitiu aplicar remoção de ruído mais agressiva e arredondamento mais grosseiro
- Maior que a menor diferença da fingerprint anterior,
Estabilizando a fingerprint com arredondamento
- Mesmo com a faixa de ruído de uma única amostra reduzida, o valor ainda oscila, então é preciso arredondar para usá-lo como fingerprint final
- Como o ruído é aplicado em relação ao valor da amostra de áudio, e não em valor absoluto, o arredondamento é feito com base em algarismos significativos, não em casas decimais
- Para distinguir os navegadores selecionados, 5 algarismos significativos eram suficientes, mas como não é possível verificar todos os navegadores e mudanças futuras, foram usados mais dígitos
- No modo privado do Safari 17, o número de cópias necessário para estabilizar cada nível de precisão de arredondamento foi o seguinte
- 6 algarismos significativos:
15,000cópias,3msno Safari 17 em um M1 MacBook aquecido - 7 algarismos significativos, mas arredondando o último dígito para múltiplos de 5:
30,000cópias,4ms - 7 algarismos significativos, mas arredondando o último dígito para o número par mais próximo:
70,000cópias,6ms - 7 ou mais algarismos significativos:
400,000cópias,12ms
- 6 algarismos significativos:
- A escolha final foi 7 algarismos significativos, com o último dígito sendo
0ou5, e o número de cópias foi aumentado para40,000para melhorar a estabilidade - Esse número arredondado passa a ser a nova fingerprint de áudio, que não muda mesmo com a proteção avançada contra fingerprint do Safari 17 ativada
- A nova fingerprint foi avaliada como tendo a mesma unicidade da impressão digital de áudio anterior
Desempenho e restrições de execução
- Em um navegador aquecido numa página vazia, o novo algoritmo é, em geral, mais lento que o anterior
- MacBook Air 2020 Safari 17.3: método anterior
2ms, novo método4ms - MacBook Air 2020 Chrome 120: método anterior
5ms, novo método8ms - iPhone 13 mini Safari 17.3: método anterior
8ms, novo método12ms - Galaxy J7 Prime Chrome 120: método anterior
33ms, novo método45ms - BrowserStack Windows 11 Firefox 121: método anterior
10ms, novo método18ms
- MacBook Air 2020 Safari 17.3: método anterior
- O desempenho do novo algoritmo piora em 1,5 a 2 vezes em relação ao anterior, mas o tempo de cálculo continua curto mesmo em dispositivos modestos
- Como o navegador delega parte do trabalho para a thread
OfflineAudioRender, a página permanece responsiva durante a maior parte do cálculo da fingerprint de áudio - A Web Audio API não pode ser usada em web workers, então não é possível calcular a fingerprint de áudio em um worker
- Para melhorar o desempenho, é possível verificar pela string do user agent se é Safari 17 ou superior e usar o novo algoritmo apenas no Safari 17+, mantendo o antigo nos demais navegadores
Diferenças entre Tor e Brave
- O Tor desativa completamente a Web Audio API, então a impressão digital de áudio é impossível
- O Brave adiciona ruído ao sinal de áudio como o Safari 17, mas de forma diferente
- O Safari multiplica cada amostra de áudio por um valor aleatório separado
- O Brave gera uma única multiplicação aleatória chamada
fudge factore aplica o mesmo valor a todas as amostras de áudio- Esse valor é mantido dentro da página
- Só muda em uma nova sessão normal ou anônima
- No Brave, por mais cópias de amostras de áudio que se criem, todas recebem o mesmo ruído, então o método matemático de remoção de ruído pensado para o Safari não funciona
- Ainda assim, o método anterior de remoção de ruído do Brave continua funcionando, e o novo método de geração de sinal que amplia a diferença entre fingerprints de navegadores pode aumentar a margem de erro tolerável
Aplicação no FingerprintJS
- O novo algoritmo de impressão digital de áudio substituiu o método anterior no FingerprintJS e foi publicado pela primeira vez na 4.2.0
- O código completo da implementação está no repositório GitHub da FingerprintJS
- A fingerprint de áudio é um dos vários sinais usados pela biblioteca open source para criar a impressão digital do navegador
- A FingerprintJS não inclui automaticamente todos os sinais disponíveis no navegador; ela analisa separadamente a estabilidade e a unicidade de cada sinal para avaliar seu impacto na precisão da fingerprint
- A fingerprint de áudio é considerada um sinal que contribui pouco para a unicidade, mas cuja alta estabilidade melhora ligeiramente a precisão geral da fingerprint
1 comentários
Comentários no Hacker News
Outra técnica interessante para identificar usuários online é a impressão digital da GPU, apresentada em 2022 com o codinome "DrawnApart"
Ela conta o número e a velocidade das unidades de execução da GPU via WebGL e mede coisas como o tempo de conclusão da renderização de vértices e o processamento de funções de stall
Hoje em dia, especialmente considerando o interesse em ataques por canal lateral, a abordagem de adicionar ruído uniforme aos valores pelos quais os dados vazam quase certamente não funciona
Isso porque, coletando mais amostras, é possível remover o ruído. Não sei por que o Safari adicionou isso. Pode tornar a coleta de impressões digitais mais trabalhosa, mas, como neste artigo, no fim parece que em geral dá para contornar de alguma forma
Parece uma espécie de teatro da privacidade, em que o mais importante passou a ser ter uma história plausível para contar ao público, e não se a solução é tecnicamente eficaz
Alguém pode explicar por que os resultados são diferentes, para começo de conversa? Por exemplo, queria entender por que a impressão digital de áudio é possível
Ao criar um pequeno sinal com a Web Audio API, todos os navegadores produzem resultados quase iguais, mas é possível diferenciá-los usando diferenças minúsculas
É uma pena que os desenvolvedores de navegadores tenham que adicionar ruído ao processamento de buffers de áudio para tentar impedir isso
Em resumo, mesmo dentro da mesma base de código, caminhos de código diferentes, como variantes SIMD, podem produzir resultados de ponto flutuante sutilmente diferentes. Isso parece estar relacionado ao fato de que operações de ponto flutuante são mais sensíveis do que se imagina à ordem das operações, entre outras coisas
Mesmo implementando corretamente o mesmo algoritmo e as mesmas fórmulas, os resultados podem variar um pouco
Corrijam-me se eu estiver errado. O motivo pelo qual o desvio da impressão digital funciona aqui parece se resumir à decisão da especificação da Web Audio API de deixar em aberto desta forma o tratamento de anti-aliasing do OscillatorNode
"Há várias abordagens práticas que uma implementação pode adotar para evitar esse aliasing. Independentemente da abordagem, o sinal de áudio digital ideal em tempo discreto é matematicamente bem definido. As concessões da implementação estão no custo de implementação em termos de uso de CPU e em quão fielmente ela chega a esse ideal. Embora se espere que as implementações tomem algum cuidado para atingir esse ideal, em hardware de baixo desempenho é razoável considerar abordagens de qualidade mais baixa e custo mais baixo."
Na minha visão, isso significa que a saída do OscillatorNode explorada aqui quase certamente não é determinística entre navegadores e até mesmo entre hardwares diferentes no mesmo navegador. A não determinismo se baseia no método de anti-aliasing escolhido pelo navegador ou nos vários caminhos escolhidos dentro do mesmo navegador conforme o hardware. Isso também inclui mudanças ou correções no mesmo algoritmo de anti-aliasing
Não sei bem por que o anti-aliasing foi deixado a cargo do navegador. Aplicativos ou bibliotecas de áudio de alta qualidade vão querer controlar totalmente a forma como evitam aliasing nos sinais que geram, e não usarão o oscilador padrão. Por outro lado, se um web app aceita um algoritmo arbitrário de anti-aliasing e as diferenças por navegador decorrentes disso, provavelmente não vai se importar muito se o algoritmo são instruções SIMD hardcoded ou um framework auxiliar JavaScript de Web Audio de 20 MB
1: https://webaudio.github.io/web-audio-api/#OscillatorNode
Fico imaginando se aqui não seria possível aplicar a mesma solução que Hixie usou ao padronizar o parser de HTML5: um especialista da área especifica um algoritmo de anti-aliasing exato e determinístico que funcione suficientemente bem, e depois todos os navegadores passam a usá-lo. A perda de desempenho mensurável provavelmente só apareceria em algo como tutoriais da Web Audio API que geram sinais com o oscilador padrão com anti-aliasing
Por isso, a ideia é permitir que a implementação decida quanto gastar conforme os recursos de computação disponíveis, bateria etc.
Foi uma tolice colocar uma API de áudio em grafo de nós no navegador. Deveria ter havido apenas AudioWorklet
https://web.archive.org/web/20120505042746/https://developer...
Repulsivo
Para começo de conversa, não entendo por que a API de áudio pode ser usada sem permissão do site. Parece algo fácil de corrigir com uma caixa de diálogo simples, tipo "Este site quer usar seu dispositivo de som".
A Internet em sua forma atual arruinou muito do sonho da computação pessoal. Empresas e Estados são poderosos demais de forma assimétrica em relação aos indivíduos. A minha tecnologia deveria poder enviar dados para um servidor sem aprovação explícita?
Por outro lado, quando limpei o cache do navegador e liguei a VPN, ele me identificou erroneamente como um novo visitante. Ainda assim, o modelo de negócios é desprezível.
Mesmo sendo uma interpretação otimista, há muito valor em publicar pesquisas assim e trazê-las à tona. Em vez de me preocupar que todo mundo vá roubar mais porque saiu um texto dizendo que uma mochila verde de uma certa marca ajuda em furtos, eu tenderia a apostar mais que as lojas passarão a perceber melhor esse método.
Em vez de somar valores aleatórios a cada amostra, parece que o Safari também poderia adicionar ruído determinístico com base em uma chave que muda a cada hora.
Se for criado como uma função das amostras de áudio e da chave, o ruído seria o mesmo dentro da mesma sessão, mas se tornaria inútil para rastreamento uma hora depois.
Para corrigir isso, é preciso eliminar o vazamento de informação em si; apenas escondê-lo sob uma camada de desvio aleatório não basta.
Por exemplo, algo como
RNG_SEED = HMAC_SHA256(PERSISTENT_SECRET,Location.origin).Agora estou realmente pronto para virar "aquela pessoa" que navega na Web com o JavaScript desligado.
Se eles conseguirem raspar só mais alguns bits de outros lugares, você pode ser identificado de forma única. Mesmo assim, para mim, esse pessoal pode ser colocado na Golgafrinchan Ark B junto com o resto da indústria de adtech.
Um site que visitei recentemente até usava marcação, mas em vez de compilá-la para HTML e servi-la estaticamente, renderizava tudo no lado do cliente com JavaScript. WTF.
Não são só verificações de DDoS como as da Cloudflare; agora até coisas que deveriam estar dentro do HTML da página são carregadas via JavaScript.
Quanto mais hostil a Internet fica, mais essa escolha vai na direção certa.
Não entendo bem como esse método consegue criar mais do que alguns milhares de combinações únicas.
Tipo de navegador × versão do navegador × versão do sistema operacional × versão do acelerador × … o que mais? Não parece haver variação suficiente para ser remotamente único.
Essa técnica faz fingerprinting com base em diferenças de hardware, drivers e sistema operacional no processamento de áudio, ou olha apenas para o software do navegador?
Imagino que tenha existido, ou ainda exista, uma técnica parecida que expõe diferenças do dispositivo gráfico subjacente.
Um dos exemplos dados no texto é a Transformada Rápida de Fourier (FFT). Todos os sistemas operacionais têm uma versão dessa função, mas ela tende a ser otimizada ao longo do tempo, e frequentemente se comporta de forma diferente em CPUs diferentes dependendo das instruções SIMD disponíveis.