O que estaba mal en password.es, e xa non

Publicado o por David Carrero

Este blog leva doce artigos explicando como deberían facerse as cousas: que a lonxitude importa máis que os símbolos, que un xestor non é comodidade senón a única forma de cumprir a regra, que unha porcentaxe non di nada.

Escribir iso é doado. O incómodo é mirar o teu propio sitio co mesmo rasero. Fixémolo, e había tres cousas mal. Van aquí enteiras, cos números que as delatan, porque un sitio de seguridade que só publica os seus acertos vale bastante menos.

O comprobador conxelábase mentres escribías

O comprobador analiza o teu contrasinal con zxcvbn, unha biblioteca que busca patróns en vez de contar maiúsculas. Funciona moi ben e ten un custo: execútase enteira, de golpe, no mesmo fío que debuxa a páxina. Mentres corre, o navegador non pode facer nada máis.

Ese custo medra rápido coa lonxitude. Medido co mesmo paquete que serve o sitio, e con contrasinais dos que a xente escribe de verdade —palabras, anos, @ no canto de a—:

lonxitude unha execución
16 caracteres 45 ms
20 caracteres 121 ms
32 caracteres 273 ms
64 caracteres 843 ms
128 caracteres 3.621 ms

Ata aquí, normal. O problema estaba en cantas veces a lanzabamos.

O campo tiña enganchados dous detectores distintos, input e keyup. Unha tecla normal dispara os dous. Así que cada vez que premías unha letra, a análise completa corría dúas veces: 90 ms nun contrasinal de 16 caracteres, medio segundo nun de 32.

E non había nada que o frease: nin un temporizador, nin un límite de lonxitude, nin un fío á parte. A partir duns vinte caracteres, o navegador tardaba máis en analizar do que ti tardabas en premer a tecla seguinte. As pulsacións acumulábanse nunha cola que xa non se baleiraba nunca, e a páxina deixaba de responder mentres escribías. Pegar un contrasinal longo conxelábaa varios segundos.

O arranxo son dous cambios pequenos. Quitamos o detector de keyup, porque input xa cobre teclear, pegar, borrar e o enchido automático do xestor: a metade do traballo desaparece sen cambiar absolutamente nada do que ves. E engadimos unha espera de 150 milisegundos: mentres escribes non se analiza nada, e analízase en canto paras. Ninguén teclea tan amodo como para notalo.

O resultado é idéntico. Barcelona1992$ segue dicindo o mesmo: que «barcelona» está no dicionario, que 1992 parece un ano, e que cae en menos dun segundo.

A descrición estaba cortada a media frase en quince idiomas

Esta é máis parva e máis vergoñenta.

A frase que aparece baixo o título no buscador —a meta description— estaba truncada en quince dos dezaoito idiomas do comprobador. Só se salvaban o castelán, o coreano e o xaponés. Alguén a recortou por lonxitude nalgún momento, cortou a media palabra, e ninguén o mirou despois.

En tres idiomas o corte caeu xusto no medio dun carácter especial, así que o que publicabamos en Google era isto:

idioma o que serviamos o que debía dicir
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 chamativo é onde estaba: na páxina que mellor funciona de todo o sitio. O comprobador converte moitísimo mellor que o xerador, e facíao coa descrición rota. Están completadas as quince.

De paso, en coreano, xaponés e vietnamita movemos a marca do principio á fin do título. No buscador o dominio xa se ve á parte, así que empezar por «password.es ·» só gastaba o espazo que máis pesa.

Un nesgo dun entre cen millóns

O xerador escolle cada carácter con crypto.getRandomValues(), a fonte de azar boa do navegador. Pero para converter ese número enorme en «unha posición do alfabeto» faciamos unha división con resto, e aí hai unha trampa clásica: 2³² non é múltiplo de 83, así que as primeiras posicións do alfabeto saían un chisco máis a miúdo que as últimas.

Canto é «un chisco»: cun alfabeto de ata 89 caracteres, da orde dunha parte en cen millóns. Non cambia nada. Non fai o teu contrasinal apreciablemente máis feble, nin de lonxe.

Arranxámolo igualmente, e son tres liñas: descártanse os 45 valores sobrantes dos 4.294.967.296 posibles e sortéase de novo. Nun sitio sobre contrasinais, «é desprezable» non é unha boa razón para deixar un nesgo posto cando quitalo custa iso.

O que faltaba: que o navegador fixese cumprir a promesa

Levamos un artigo enteiro explicando que o teu contrasinal non sae de aquí. Era verdade, e aínda así era só unha frase nosa: nada impedía tecnicamente que un script inxectado fixese outra cousa.

Agora cada páxina leva unha política de seguridade de contido. As dúas partes que importan:

  • Non se executa ningún script que non estivese na páxina ao construíla. Cada guión lexítimo vai asinado coa súa pegada; un inxectado non coincide e o navegador négase a executalo.
  • connect-src 'none'. O sitio non fai nin unha soa petición de rede desde JavaScript, e agora imponno o navegador. Se algún día algo intentase mandar a algunha parte o que escribes, non sairía.

A promesa deixou de ser unha declaración e pasou a ser unha regra.

O que segue sen estar ben

Actualización do 31 de agosto. As tres cousas desta sección arranxáronse o mesmo día en que se publicou este artigo: os quince idiomas xa describen o motor real, as dúas escalas son unha, e as preguntas frecuentes do comprobador explican o dos símbolos. Déixanse escritas, porque o rexistro do que estivo mal vale máis que a foto dun sitio impecable.

Aquí é onde este artigo gaña o seu sitio.

Quince idiomas seguen describindo o comprobador como o motor antigo. O texto desas páxinas di que reproduce a lóxica clásica de PasswordMeter. Xa non: ese motor cambiouse porque daba «moi forte» a Contrasinal1! e suspendía unha frase longa de cinco palabras, que é exactamente ao revés do que hai que dicir. O castelán, o coreano e o xaponés están actualizados; os outros quince, non.

Hai dúas escalas distintas na mesma casa. A portada decide se un contrasinal é forte polos seus bits; o comprobador decídeo polo tempo que custaría rompelo. Criterios distintos, e en ningún sitio o avisamos.

O xerador e o comprobador non contan os mesmos símbolos: un usa 27, o outro supón 33. A diferenza é pequena, pero está aí.

Ningunha das tres é grave. As tres son débeda, e prefiren estar escritas aquí que agardando a que as atope outro.

O rexistro desta versión

Como o repositorio non é público, o rexistro de cambios vai aquí enteiro. Versión 0.2.0, do 31 de agosto de 2026:

Engadido. Política de seguridade de contido por páxina, coa pegada de cada guión. O artigo sobre onde están os teus contrasinais gardados, nos dezaoito idiomas. Unha cola editorial que decide que se escribe, e que manda non publicar nada se queda baleira.

Corrixido. A descrición do comprobador, cortada a media frase en quince idiomas, tres deles cun carácter partido pola metade. O bloqueo da lapela ao teclear. O nesgo do sorteo. E a foto que faltaba no artigo anterior.

Cambiado. O título do comprobador en coreano, xaponés e vietnamita. O despregamento, que agora se dispara cando o sitio construído xa existe e non un minuto antes. E as traducións ao vietnamita, hindi e árabe, que deixan de bloquear unha publicación aínda que sigan sendo as máis febles.


As cifras deste artigo están medidas, non estimadas: os tempos de zxcvbn co mesmo paquete que serve o sitio e contrasinais con palabras e substitucións; o nesgo do sorteo, calculado sobre os 4.294.967.296 valores dun enteiro de 32 bits. O motor do comprobador é zxcvbn, de código aberto.

Foto de Ernandes Alves · Pexels

← Volver ao blog