Descobrimos um identificador estável do Firefox que conecta todas as identidades privadas do Tor do usuário
(fingerprint.com)- Apenas a ordem de retorno de
indexedDB.databases()já permite gerar um identificador estável que persiste durante a vida do processo em navegadores baseados em Firefox - Esse identificador é compartilhado além do escopo de origin, permitindo que sites sem relação entre si observem o mesmo valor dentro do mesmo runtime do navegador e o usem para rastreamento cross-origin
- No Private Browsing do Firefox, o identificador continua existindo se o processo seguir vivo mesmo após fechar todas as janelas privadas, e permanece até depois de um New Identity no Tor Browser
- A causa está na implementação do IndexedDB no Gecko, que mapeia nomes de bancos de dados privados para nomes de arquivo baseados em UUID e expõe o resultado sem ordenação
- A Mozilla distribuiu a correção no Firefox 150 e no ESR 140.10.0, e projetar o sistema sem expor a ordem interna do armazenamento é essencial para proteger a privacidade
Visão geral da vulnerabilidade
- Em todos os navegadores baseados em Firefox, é possível extrair um identificador que persiste durante a vida do processo pela ordem dos itens retornados por
indexedDB.databases()- Se um site criar vários bancos de dados IndexedDB e depois verificar a ordem de retorno, ele pode gerar um identificador único e determinístico do processo do navegador em execução
- Esse comportamento aparece no escopo do processo, não no escopo de origin, então até sites sem relação entre si podem observar o mesmo identificador dentro do mesmo runtime do navegador
- No Private Browsing do Firefox, o identificador permanece se o processo do Firefox continuar em execução mesmo depois de fechar todas as janelas privadas
- No Tor Browser, o identificador estável continua existindo até depois de um New Identity, que apaga cookies e histórico e usa um novo circuito Tor
- Isso entra em conflito com a expectativa de que a atividade posterior do navegador não possa ser vinculada à atividade anterior, enfraquecendo a garantia de não vinculação na qual o usuário confia
- Foi feita uma divulgação responsável à Mozilla e ao Tor Project
- A Mozilla distribuiu a correção no Firefox 150 e no ESR 140.10.0
- O patch está sendo acompanhado no Mozilla Bug 2024220, e a causa está na implementação do IndexedDB do Gecko, afetando também o Tor Browser e outros navegadores baseados em Firefox
- O princípio da correção é simples
- O navegador não deve expor externamente a ordem interna do armazenamento no escopo do processo
- Se os resultados forem normalizados ou retornados em ordem classificada, é possível eliminar a entropia e bloquear o abuso desse identificador estável
Por que isso importa
- O modo de navegação privada e os navegadores focados em privacidade existem para dificultar a identificação do usuário em contextos diferentes
- Expectativa geral 1: na ausência de armazenamento compartilhado ou de mecanismos explícitos de identidade, sites sem relação entre si não deveriam conseguir saber se estão interagindo com a mesma instância do navegador
- Expectativa geral 2: quando uma sessão privada termina, as informações associadas a ela também deveriam desaparecer
- Esse comportamento quebra as duas expectativas
- Um site pode derivar um identificador apenas a partir do comportamento interno de armazenamento do navegador, sem cookies, localStorage ou canais explícitos entre sites
- A ordem dos nomes de bancos de dados retornada pela API fornece um sinal de identificação de alta capacidade
- Há uma lição importante do ponto de vista de desenvolvimento
- Vulnerabilidades de privacidade não surgem apenas do acesso direto a dados identificadores
- Também pode haver vazamento de privacidade quando detalhes internos de implementação são expostos de forma determinística
- Ponto central sob a ótica de segurança e produto
- Mesmo uma API aparentemente inofensiva pode virar um vetor de rastreamento entre sites se vazar um estado estável em nível de processo
IndexedDB e indexedDB.databases()
- IndexedDB é uma API de navegador para armazenamento estruturado de dados no lado do cliente
- Aplicações web a utilizam para suporte offline, cache, estado de sessão e outros fins de armazenamento local
- Cada origin pode criar um ou mais bancos de dados nomeados, com object stores e armazenamento de grandes volumes de dados
indexedDB.databases()retorna metadados dos bancos de dados visíveis para o origin atual- Desenvolvedores podem usar isso para verificar bancos existentes, depurar uso de armazenamento e gerenciar o estado da aplicação
- Sob expectativas normais de proteção de privacidade, a própria ordem de retorno dessa API não deveria carregar informações identificadoras
- É necessária uma representação neutra ou normalizada dos metadados dos bancos de dados
- O problema real foi que, em navegadores baseados em Firefox, a ordem de retorno não era neutra de forma alguma
Como indexedDB.databases() virou um identificador estável
- No Private Browsing do Firefox,
indexedDB.databases()retorna metadados em uma ordem derivada da estrutura interna de armazenamento, e não da ordem de criação dos bancos de dados- A implementação relacionada fica em
dom/indexedDB/ActorsParent.cpp
- A implementação relacionada fica em
- No Private Browsing, os nomes dos bancos de dados não são usados diretamente como identificadores em disco
- Em vez disso, eles são mapeados para uma base de nome de arquivo baseada em UUID por meio da tabela hash global
StorageDatabaseNameHashtable = nsTHashMap<nsString, nsString> - Esse mapeamento ocorre em
GetDatabaseFilenameBase()dentro deOpenDatabaseOp::DoDatabaseWork()
- Em vez disso, eles são mapeados para uma base de nome de arquivo baseada em UUID por meio da tabela hash global
- Quando
aIsPrivateé true, o nome do banco de dados fornecido pelo site é substituído por um UUID gerado e armazenado naStorageDatabaseNameHashtableglobal- A chave usa apenas a string do nome do banco de dados
- Persiste durante a vida do QuotaClient do IndexedDB
- É compartilhado entre todos os origins
- Só é reinicializado quando o Firefox é totalmente reiniciado
- Depois, ao chamar
indexedDB.databases(), o Firefox coleta os nomes de arquivo dos bancos emGetDatabasesOp::DoDatabaseWork()por meio deQuotaClient::GetDatabaseFilenames(...)- Os nomes-base dos bancos são inseridos em um
nsTHashSet - Nenhuma ordenação é feita antes da iteração
- Os nomes-base dos bancos são inseridos em um
- A ordem final dos resultados é determinada pelo percurso do layout interno dos buckets do conjunto hash
- Como o mapeamento UUID permanece estável durante a vida do processo do Firefox, a ordem retornada também permanece como uma função determinística dos valores UUID gerados, do comportamento da função de hash, da capacidade da tabela hash e do histórico de inserção
- Essa ordem persiste entre abas e janelas privadas, sendo redefinida apenas com um reinício completo do Firefox
- Tanto o mapeamento UUID quanto a iteração do conjunto hash existem no escopo do processo, e não no escopo de origin
Como reproduzir
- É possível demonstrar o comportamento com um PoC simples
- Dois origins diferentes hospedam o mesmo script
- Cada script cria bancos de dados com um conjunto fixo de nomes, chama
indexedDB.databases(), extrai a ordem retornada e a imprime
- Em builds afetadas do Firefox Private Browsing e do Tor Browser, os dois origins observam a mesma permutação durante a vida do mesmo processo do navegador
- Ao reiniciar o navegador, a permutação muda
- Exemplo conceitual de saída
- Ordem de criação:
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p - Ordem de retorno:
g,c,p,a,l,f,n,d,j,b,o,h,e,m,i,k
- Ordem de criação:
- O ponto principal não é a ordem exata em si
- Ela difere da ordem de criação original
- A mesma ordem aparece em origins sem relação entre si
- Persiste após recarregar a página, abrir uma nova janela privada e até depois de fechar todas as janelas privadas
- Só uma reinicialização completa do navegador gera uma nova ordem
- Isso permite verificar diretamente uma propriedade indesejada do ponto de vista da privacidade
Impacto na privacidade
- Essa vulnerabilidade permite tanto rastreamento cross-origin quanto same-origin dentro de um único runtime do navegador
-
Impacto cross-origin
- Sites sem relação entre si podem derivar independentemente o mesmo identificador e inferir que estão interagindo com o mesmo processo em execução do Firefox ou do Tor Browser
- Torna possível vincular atividades entre domínios mesmo sem cookies ou outro armazenamento compartilhado
-
Impacto same-origin
- No Private Browsing do Firefox, o identificador permanece se o processo do Firefox continuar em execução mesmo depois de todas as janelas privadas serem fechadas
- Um site pode reconhecer novamente visitas posteriores que aparentam ser uma nova sessão privada
- No Tor Browser, o identificador estável praticamente neutraliza o isolamento de New Identity dentro do processo do navegador em execução
- Isso permite vincular sessões que deveriam estar totalmente separadas
-
Por que isso é especialmente grave no Tor Browser
- O Tor Browser foi projetado para reduzir a possibilidade de ligação entre sites e minimizar a identificação em nível de instância do navegador
- Um identificador estável que persiste durante a vida do processo entra em choque direto com esse objetivo de design
- Mesmo sobrevivendo apenas até um reinício completo do processo, isso já basta para enfraquecer a não vinculação durante uso ativo
Entropia e capacidade de fingerprinting
- Esse sinal não é apenas estável, como também tem alta capacidade
- Se um site controla
Nnomes de bancos de dados, o número de permutações observáveis éN! - A entropia teórica é
log2(N!)
- Se um site controla
- Com 16 nomes controláveis, o espaço teórico é de cerca de 44 bits
- Um nível suficiente para distinguir instâncias simultâneas de navegador em ambientes reais
- Por causa do comportamento da tabela hash interna, o número de permutações realmente atingível pode ser um pouco menor
- Mas isso não muda o ponto central do ponto de vista de segurança
- A ordem exposta ainda fornece entropia suficiente para funcionar como um identificador forte
Como corrigir
- A correção correta é interromper a exposição de entropia derivada do layout interno do armazenamento
- A mitigação mais limpa é retornar os resultados em uma ordem canônica, como ordenação lexicográfica
- Isso preserva a utilidade da API para desenvolvedores enquanto remove o sinal de fingerprinting
- Randomizar a saída a cada chamada também poderia ocultar a ordem estável
- Ainda assim, ordenar é uma opção mais simples, previsível e fácil para desenvolvedores entenderem
- Condições ideais da correção sob a ótica de engenharia de segurança
- Baixa complexidade conceitual
- Risco mínimo de compatibilidade
- Eliminação direta do vazamento de privacidade
Divulgação responsável
- Foi feita uma divulgação responsável à Mozilla e ao Tor Project
- A Mozilla distribuiu a correção no Firefox 150 e no ESR 140.10.0
- O patch está sendo acompanhado no Mozilla Bug 2024220
- A origem do comportamento está na implementação do IndexedDB do Gecko
- Navegadores derivados do Gecko, incluindo o Tor Browser, também entram na área de impacto se não tiverem uma mitigação própria
Design centrado em privacidade
- Até pequenos detalhes de implementação podem levar a problemas relevantes de privacidade
- Sites sem relação entre si podem vincular atividades além do origin durante o mesmo runtime do navegador
- O identificador sobrevive mais tempo do que o usuário espera, enfraquecendo os limites de sessões privadas
- O lado positivo é que a correção é simples e eficaz
- Normalizar a saída antes de retorná-la remove essa fonte de entropia
- Isso permite restaurar os limites de privacidade esperados
- É um tipo de vulnerabilidade fácil de ignorar, mas com grande impacto e que merece atenção especial ao criar funcionalidades sensíveis à privacidade
Ainda não há comentários.