O que estava mal no password.es, e já não está

Publicado a por David Carrero

Este blogue tem doze artigos a explicar como as coisas deviam ser feitas: que o comprimento importa mais do que os símbolos, que um gestor não é comodidade mas a única forma de cumprir a regra, que uma percentagem não diz nada.

Escrever isso é fácil. O incómodo é olhar para o próprio sítio com a mesma bitola. Fizemo-lo, e havia três coisas mal. Vão aqui inteiras, com os números que as denunciam, porque um sítio de segurança que só publica os seus acertos vale bastante menos.

O verificador bloqueava enquanto escrevias

O verificador analisa a tua palavra-passe com zxcvbn, uma biblioteca que procura padrões em vez de contar maiúsculas. Funciona muito bem e tem um custo: corre toda de uma vez, na mesma linha de execução que desenha a página. Enquanto corre, o navegador não pode fazer mais nada.

Esse custo cresce depressa com o comprimento. Medido com o mesmo pacote que o sítio serve, e com palavras-passe como as que as pessoas escrevem mesmo — palavras, anos, @ em vez de a:

comprimento uma execução
16 caracteres 45 ms
20 caracteres 121 ms
32 caracteres 273 ms
64 caracteres 843 ms
128 caracteres 3.621 ms

Até aqui, normal. O problema era quantas vezes a lançávamos.

O campo tinha dois ouvintes ligados, input e keyup. Uma tecla normal dispara os dois. Por isso, a cada letra escrita, a análise completa corria duas vezes: 90 ms numa palavra-passe de 16 caracteres, meio segundo numa de 32.

E nada a travava: nem temporizador, nem limite de comprimento, nem linha de execução à parte. A partir de uns vinte caracteres, o navegador demorava mais a analisar do que tu a carregar na tecla seguinte. As teclas acumulavam-se numa fila que já não esvaziava, e a página deixava de responder enquanto escrevias. Colar uma palavra-passe longa congelava-a durante segundos.

A correção são duas mudanças pequenas. Tirámos o ouvinte keyup, porque input já cobre escrever, colar, apagar e o preenchimento automático do gestor: metade do trabalho desaparece sem mudar absolutamente nada do que vês. E acrescentámos uma espera de 150 milissegundos: enquanto escreves não se analisa nada, e analisa-se assim que paras. Ninguém escreve devagar ao ponto de notar.

O resultado é idêntico. Barcelona1992$ continua a dizer o mesmo: que «barcelona» está no dicionário, que 1992 parece um ano, e que cai em menos de um segundo.

A descrição estava cortada a meio da frase em quinze idiomas

Esta é mais tola e mais vergonhosa.

A frase que aparece por baixo do título no motor de busca — a meta description — estava truncada em quinze dos dezoito idiomas do verificador. Só se salvavam o espanhol, o coreano e o japonês. Alguém a cortou por comprimento a certa altura, cortou a meio da palavra, e ninguém olhou depois.

Em três idiomas o corte caiu mesmo no meio de um caractere especial, por isso o que publicávamos no Google era isto:

idioma o que servíamos o que devia dizer
português …datas e padr&o padrões
turco …arıyor ve ger&cced gerçekten
vietnamita …chúng tôi tra mật kh&# mật khẩu

O que salta à vista é onde estava: na página que melhor funciona de todo o sítio. O verificador converte muitíssimo melhor do que o gerador, e fazia-o com a descrição partida. As quinze estão completas.

Já agora, em coreano, japonês e vietnamita passámos a marca do princípio para o fim do título. No motor de busca o domínio já aparece à parte, portanto começar por «password.es ·» só gastava o espaço que mais pesa.

Um viés de um em cem milhões

O gerador escolhe cada caractere com crypto.getRandomValues(), a boa fonte de acaso do navegador. Mas para transformar esse número enorme em «uma posição do alfabeto» fazíamos uma divisão com resto, e aí há uma armadilha clássica: 2³² não é múltiplo de 83, por isso as primeiras posições do alfabeto saíam um bocadinho mais vezes do que as últimas.

Quanto é «um bocadinho»: com um alfabeto até 89 caracteres, na ordem de uma parte em cem milhões. Não muda nada. Não torna a tua palavra-passe mensuravelmente mais fraca, nem de longe.

Corrigimos à mesma, e são três linhas: descartam-se os 45 valores excedentes dos 4.294.967.296 possíveis e sorteia-se outra vez. Num sítio sobre palavras-passe, «é desprezável» não é boa razão para deixar um viés quando tirá-lo custa isso.

O que faltava: que o navegador fizesse cumprir a promessa

Temos um artigo inteiro a explicar que a tua palavra-passe não sai daqui. Era verdade, e ainda assim era só uma frase nossa: nada impedia tecnicamente que um script injetado fizesse outra coisa.

Agora cada página leva uma política de segurança de conteúdo. As duas partes que importam:

  • Não corre nenhum script que não estivesse na página ao construí-la. Cada script legítimo vai assinado com a sua impressão digital; um injetado não corresponde e o navegador recusa-se a executá-lo.
  • connect-src 'none'. O sítio não faz um único pedido de rede a partir de JavaScript, e agora é o navegador que o impõe. Se um dia algo tentasse mandar para algum lado aquilo que escreves, não sairia.

A promessa deixou de ser uma declaração e passou a ser uma regra.

O que continua mal

Atualização de 31 de agosto. As três coisas desta secção foram corrigidas no mesmo dia em que este artigo saiu: os quinze idiomas já descrevem o motor real, as duas escalas são uma, e as perguntas frequentes do verificador explicam o caso dos símbolos. Ficam escritas, porque o registo do que esteve mal vale mais do que a fotografia de um sítio impecável.

É aqui que este artigo ganha o seu lugar.

Quinze idiomas continuam a descrever o verificador como o motor antigo. O texto dessas páginas diz que reproduz a lógica clássica do PasswordMeter. Já não: esse motor foi trocado porque dava «muito forte» a Palavra1! e chumbava uma frase longa de cinco palavras, que é exatamente o contrário do que há a dizer. O espanhol, o coreano e o japonês estão atualizados; os outros quinze, não.

Há duas escalas diferentes na mesma casa. A página inicial decide se uma palavra-passe é forte pelos seus bits; o verificador decide pelo tempo que custaria parti-la. Critérios diferentes, e em lado nenhum o avisamos.

O gerador e o verificador não contam os mesmos símbolos: um usa 27, o outro supõe 33. A diferença é pequena, mas está lá.

Nenhuma das três é grave. As três são dívida, e preferem estar escritas aqui a ficar à espera de que as encontre outra pessoa.

O registo desta versão

Como o repositório não é público, o registo de alterações vai aqui inteiro. Versão 0.2.0, de 31 de agosto de 2026:

Adicionado. Política de segurança de conteúdo por página, com a impressão digital de cada script. O artigo sobre onde estão as tuas palavras-passe guardadas, nos dezoito idiomas. Uma fila editorial que decide o que se escreve, e que manda não publicar nada quando fica vazia.

Corrigido. A descrição do verificador, cortada a meio da frase em quinze idiomas, três deles com um caractere partido ao meio. O bloqueio do separador ao escrever. O viés do sorteio. E a foto que faltava no artigo anterior.

Alterado. O título do verificador em coreano, japonês e vietnamita. O lançamento, que agora dispara quando o sítio construído já existe e não um minuto antes. E as traduções para vietnamita, hindi e árabe, que deixam de bloquear uma publicação apesar de continuarem a ser as mais frágeis.


Os números deste artigo são medidos, não estimados: os tempos do zxcvbn com o mesmo pacote que o sítio serve e palavras-passe com palavras e substituições; o viés do sorteio, calculado sobre os 4.294.967.296 valores de um inteiro de 32 bits. O motor do verificador é zxcvbn, de código aberto.

Foto de Ernandes Alves · Pexels

← Voltar ao blog