Só me deixe digitar alguns números
(gendignoux.com/blog)- A caixa de entrada de autenticação por e-mail de 6 dígitos do sistema de login do governo suíço AGOV não conseguia processar a digitação de números em teclados franceses AZERTY, impedindo o próprio cadastro da conta
- O JavaScript da caixa de entrada interceptava as teclas e armazenava o código de autenticação em uma variável separada, mas ignorava a tecla Shift, na prática bloqueando o layout AZERTY, que exige Shift para digitar números
- O mesmo erro ocorria em várias combinações de Firefox·Chromium·Chrome·Safari com Linux·macOS, mas funcionava normalmente em teclados QWERTY, restringindo a causa a um problema de layout de teclado, não de navegador ou sistema operacional
- O suporte oficial também exigia passar pela mesma autenticação por e-mail, e não havia alternativas como e-mail ou telefone; assim, usuários que não conseguiam fazer login também não conseguiam reportar o bug de login
- Usar lógica complexa de tratamento de teclas em vez de campos de entrada nativos, e amarrar o produto e os canais de suporte ao mesmo fluxo de autenticação, derruba ao mesmo tempo a acessibilidade e a resposta a incidentes; por isso, são necessários entrada simples baseada no DOM e canais de suporte independentes
AGOV como infraestrutura de identidade digital
- Identidade digital se tornou recentemente um dos grandes debates da web, acompanhada de várias interdependências e controvérsias
- O impacto das leis de verificação de idade sobre o anonimato online
- A possibilidade de a Wikipedia ter de verificar a identidade dos usuários no Reino Unido
- O problema de depender do iOS e do Android oficiais como plataformas obrigatórias para carteiras de identidade digital
- Um caso em que contas digitais foram canceladas nos EUA por a pessoa ser juíza do Tribunal Penal Internacional
- O sistema de login do governo suíço AGOV está em operação desde 2024 e chegou a 1,6 milhão de contas
- Ele vem sendo ampliado como meio de login para vários serviços governamentais, incluindo o uso do seguro-desemprego e a declaração obrigatória de impostos
- No cantão de Zurique, é o único meio de login para acessar a solicitação de cidadania
Cadastro travado na etapa de verificação por e-mail
- O processo de cadastro do AGOV começa com o envio de um endereço de e-mail e a inserção de um código de verificação de 6 dígitos
- A interface do código de verificação é composta por 6 caixas de entrada, uma para cada dígito
- Ao digitar um número, o foco não passa para a próxima caixa
- Os números continuam se acumulando na caixa atual, que muda para um estado de erro em vermelho
- Mesmo avançando manualmente e preenchendo um dígito por vez, no fim aparece o erro
field required
- Foi feita uma tentativa de alterar diretamente os valores do DOM nas ferramentas de desenvolvedor, mas não havia valores de formulário visíveis, e nenhum erro era registrado no console web
- O resultado foi o mesmo usando outros endereços de e-mail ou endereços falsos como
test@example.comexample.comé um domínio reservado conforme a RFC 6761
Descartando navegador e sistema operacional
- No início, suspeitou-se que a combinação Firefox e Linux não fosse compatível ou que o CAPTCHA tivesse falhado
- Pouco antes de o formulário do código de verificação aparecer, havia uma conexão com
eu-api.friendlycaptcha.eu - A documentação oficial de requisitos lista apenas Windows e macOS como sistemas operacionais compatíveis
- Por outro lado, o guia de chaves de segurança diz que Linux e Firefox também são compatíveis
- Pouco antes de o formulário do código de verificação aparecer, havia uma conexão com
- O mesmo erro ocorreu nas seguintes 6 combinações de ambiente
- Firefox, Chromium e Chrome no Linux
- Firefox, Safari e Chrome no macOS
- Em um notebook de trabalho, depois de digitar, o foco passava automaticamente para a próxima caixa, e também aparecia corretamente o erro
Code entered is incorrect, indicando código incorreto em vez de código vazio - No computador macOS de uma amiga, os três navegadores também aceitaram o código de verificação
- Não era possível depender de um computador fornecido pelo empregador para interagir com serviços governamentais no longo prazo; além disso, mesmo que o cadastro fosse feito no computador de trabalho, ainda havia a possibilidade de não conseguir fazer login no notebook pessoal
Estrutura de suporte que também impedia reportar o problema
- O suporte oficial era oferecido apenas por formulário web, e esse formulário também exigia primeiro inserir um código de verificação por e-mail
- A FAQ afirma que o suporte das instituições participantes é oferecido durante o horário comercial somente pela criação de tickets online
- Não havia e-mail nem telefone, além do endereço postal da Chancelaria Federal Suíça
- O recurso de feedback para deixar elogios, críticas ou solicitações ao AGOV também exige login com AGOV ou uma conta equivalente
- Usuários que falhavam na verificação por e-mail caíam numa dependência circular, sem poder reportar o problema por causa do mesmo fluxo de autenticação
-
AGOV Access e dispositivos compatíveis
- O app AGOV Access para Android tinha nota 1,4, mas não foi encontrado o mesmo problema de código de verificação nas avaliações do Google Play
- Nas avaliações, havia muitos pedidos de suporte ao GrapheneOS, sistema operacional derivado do Android com foco em segurança e privacidade
- Segundo a FAQ oficial, o app não funciona porque o framework reforçado contra modificações não autorizadas é incompatível com o GrapheneOS
- A Chancelaria Federal instruiu o fornecedor a garantir compatibilidade
- Atualmente, os métodos de segundo fator para cadastro e login são um smartphone iOS·Android padrão permitido ou uma chave de segurança; em ambos os casos, antes é necessário passar pela verificação por e-mail
A causa encontrada no JavaScript
- A página carregava poucos recursos, mas o principal arquivo JavaScript minimizado e não ofuscado tinha 2,4 MB e, expandido, passava de 100 mil linhas
- Ao buscar pela string
field required, foi encontrada a lógica que define o estado do código de verificação- Se a variável do código de verificação não existir, o estado é definido como
REQUIRED - Se o comprimento for diferente do comprimento exigido para o código, ele é tratado como
WRONG - Se o comprimento estiver correto, usa
VALIDou um estado de erro conforme o resultado da verificação de e-mail no servidor
- Se a variável do código de verificação não existir, o estado é definido como
- A função
verificationCodeEnteredintercepta as teclas e coleta o código de verificação em uma variável JavaScriptEnterexecuta o callback de verificaçãoBackspaceapaga o valor atual- As setas e
Tabmovem entre as caixas de entrada - Teclas comuns são convertidas em número com
Number(S.key)e armazenadas no código - Teclas como
Control,Meta,Shift,versão retornadas sem processamento
- Como, no envio do formulário, os valores do DOM não são lidos, alterar as caixas de entrada pelas ferramentas de desenvolvedor ou por extensões do navegador não se reflete no estado mantido separadamente pelo JavaScript
Por que os números eram bloqueados apenas no AZERTY
- O layout francês padrão AZERTY exige a tecla Shift para digitar números
- Como o código ignorava o Shift, no AZERTY não era possível armazenar os próprios números como código de verificação
- O computador de trabalho usava layout QWERTY em inglês, e nenhuma das pessoas que ajudaram a confirmar o problema era francesa
- Como resultado, entre os dispositivos testados, parecia que apenas os dois notebooks pessoais estavam com defeito
- Ao trocar o layout de teclado no sistema operacional para outro layout, a digitação voltou ao normal nos notebooks pessoais
- Inversamente, ao mudar um dispositivo que funcionava para o layout francês, o mesmo erro foi reproduzido
- O teclado suíço padrão em francês pertence à família QWERTZ, comum na Europa Central
- Ele permite digitar francês e alemão com eficiência e não exige Shift para números, então o mesmo erro não aparece
- Segundo o Swiss Federal Statistical Office, há cerca de 171 mil residentes de nacionalidade francesa na Suíça, e esse número não inclui trabalhadores transfronteiriços que precisam interagir com o governo suíço
Limitações da investigação até a abertura do código-fonte
- Segundo a FAQ do AGOV, o código-fonte do AGOV deve ser publicado em dezembro de 2026 para cumprir requisitos legais
- O artigo 9º da EMBAG exige que órgãos federais publiquem o código-fonte de softwares que desenvolvem diretamente ou cuja criação encomendam para cumprir suas atribuições
- Exceções se aplicam quando direitos de terceiros ou motivos de segurança impedem ou limitam a publicação
- O escopo de publicação inclui a versão do AGOV que atingiu os objetivos do projeto, incluindo o AGOV e-ID Verifier, e versões posteriores devem ser publicadas por meio de notas de versão preparadas após cada lançamento
- Embora alguns serviços já usem o AGOV como login obrigatório, o código-fonte ainda não foi publicado, dificultando que usuários avisem desenvolvedores diretamente sobre bugs ou compartilhem soluções alternativas
O escopo da verificação de identidade confirmado após o cadastro
- Depois de alterar o layout do teclado, o endereço de e-mail foi verificado e o cadastro foi concluído com uma chave de segurança
- Durante o cadastro, foram informados nome, telefone e data de nascimento, mas essas informações não foram verificadas
- Na etapa básica de cadastro, apenas duas coisas foram confirmadas
- O endereço de e-mail realmente existe
- O método de segundo fator é uma chave de segurança de um modelo permitido ou o app AGOV Access em execução em um dispositivo Android·iOS permitido
- O AGOV é robusto contra tomada de conta por phishing remoto, mas, na etapa básica de cadastro, não impede que alguém crie uma conta usando o nome e os dados de identidade de outra pessoa
- Uma verificação adicional mostrou que, ao acessar serviços classificados como sensíveis, é necessária verificação de identidade
- Logo após o cadastro, esses serviços ainda não haviam sido acessados
- O bug foi reportado pelo formulário de suporte, mas não houve resposta
Lições do projeto
-
Projeto frágil de entrada e suporte
- A abordagem de criar uma UI vistosa com 6 campos de entrada e lógica JavaScript complexa não é robusta
- É melhor usar um único campo de entrada nativo do navegador e estilizar apenas a aparência visual com CSS
- Quando a lógica do formulário é totalmente separada do DOM, os valores do DOM não podem ser lidos no envio, e usuários avançados ou extensões do navegador também não conseguem corrigir o valor inserido
- Se houver apenas um canal de suporte, quando esse próprio canal quebra, desaparece o meio de contato; por isso é necessário um segundo canal, como e-mail ou telefone
- Aplicar a mesma lógica de login ao produto principal e ao canal de suporte faz com que relatos de bugs de usuários que não conseguem fazer login sejam perdidos
- É pelo mesmo motivo que vários serviços de internet mantêm páginas de status em domínios separados
- Colocar solicitações de suporte atrás de verificação por e-mail pode reduzir spam, mas também reduz relatos de falhas de usuários reais
- Se o código-fonte só for publicado depois que o uso já se tornou obrigatório em alguns sistemas, a solução de problemas por usuários e o compartilhamento de bugs e contornos ficam limitados
- A publicação legal do código-fonte vai além de uma simples exigência de conformidade e também é útil para investigar falhas reais
-
A web aberta ajudou na investigação
- Como a lógica JavaScript relevante não estava ofuscada, algumas buscas por strings bastaram para encontrar a causa
- Não foram necessários descompiladores avançados nem LLMs caros
- Se o código estivesse ofuscado ou compilado para WebAssembly, entender a causa teria levado muito mais tempo
- Como o código não era distribuído apenas em sistemas operacionais fechados aprovados, mas disponibilizado na web aberta, foi possível baixá-lo e investigá-lo mesmo em forma minimizada
-
Condições que permitiram identificar a causa
- Comparar vários notebooks com layouts de teclado diferentes permitiu reduzir cedo a possibilidade de problema específico de navegador ou de rede
- Ainda assim, a coleta inicial de evidências levou tempo, pois foi necessário capturar sistematicamente as telas de cada combinação de navegador para confirmar que não era erro do usuário
1 comentários
Opiniões do Lobste.rs
Uma das práticas que mais odeio na internet é quando sites interceptam a digitação e processam tudo do próprio jeito, em vez de simplesmente deixar o navegador lidar com isso
Sites que proíbem copiar e colar em campos de senha são muito mais comuns, mas isso é da mesma categoria e talvez pareça ainda pior
Na maioria das vezes isso só aumenta a complexidade por motivos forçados
A abordagem de usar um campo por caractere virou uma praga
Uma empresa adotou isso porque parecia estiloso, e agora todo mundo está fazendo sua própria versão
Mesmo sem ler com atenção, o usuário percebe na hora que não é um campo de senha
Como caso relacionado, há Medium once had a bug like this which prevented entering the character 'Ś'
Pensei em outras formas de implementar isso, mas no fim não consigo encontrar nada melhor do que um
<input type="text" />comumAté fico em dúvida sobre usar decoração em CSS que faça isso parecer muito diferente de um campo normal. Dá para duplicar visualmente o valor digitado em caixas grandes, mas aí surgem todo tipo de questão, como o que fazer quando o usuário digita mais do que o tamanho permitido, e os benefícios não parecem grandes o bastante para justificar o esforço. No máximo eu mudaria a fonte e o tamanho do campo
1224em vez de1234A forma mais rápida de corrigir é clicar no segundo
2e apertar3, mas isso não dá para fazer só com HTML+CSS<input type="text" pattern="[0-9]+" minlength=6 maxlength=6>para que ele pareça visualmente seis caixinhasUma forma mais simples seria o usuário digitar em um único campo de texto e o JavaScript desenhar seis caixas em outro ponto do DOM, atualizando tudo pelo evento
inputdisparado a cada teclaÉ difícil ter certeza de qual opção seria melhor em termos de acessibilidade. Do ponto de vista de leitor de tela, a segunda opção — um
<input>normal junto com um<canvas alt="">decorativo — talvez até seja melhor, e a navegação por teclado não ficaria estranha. Mas para usuários que dependem de recursos assistivos além de leitores de tela, esconder visualmente o<input>pode virar um desastre de acessibilidade, então eu seria muito cautelosoComo muitos serviços fazem, também daria para fornecer o código e um link de ativação no e-mail
Isso também pode resolver o mesmo problema
Pode parecer uma situação excepcional, mas acessibilidade é justamente lidar bem com esse tipo de exceção
O Tridactyl também tem exatamente o mesmo problema https://github.com/tridactyl/tridactyl/issues/3257
Foi reportado pela primeira vez em 2019, então talvez esse caso ao menos faça o pessoal criar vergonha e corrigir
Isso mostra mais uma vez que dá muito mais trabalho fazer um site quebrado ou lento do que simplesmente fazer um site que funcione