Este blog lleva doce artículos explicando cómo deberían hacerse las cosas: que la longitud importa más que los símbolos, que el gestor no es comodidad sino la única forma de cumplir la regla, que un porcentaje no dice nada.
Es fácil escribir eso. Lo incómodo es mirar tu propio sitio con el mismo rasero. Lo hemos hecho, y había tres cosas mal. Van aquí enteras, con los números que las delatan, porque un sitio de seguridad que solo publica sus aciertos vale bastante menos.
El comprobador se congelaba mientras escribías
El comprobador analiza tu contraseña con zxcvbn, una biblioteca que busca patrones en vez de contar mayúsculas. Funciona muy bien y tiene un coste: se ejecuta entera, de golpe, en el mismo hilo que dibuja la página. Mientras corre, el navegador no puede hacer nada más.
Ese coste crece rápido con la longitud. Medido con el mismo paquete que sirve el
sitio, y con contraseñas de las que la gente escribe de verdad —palabras, años,
sustituciones tipo @ por a—:
| longitud | una ejecución |
|---|---|
| 16 caracteres | 45 ms |
| 20 caracteres | 121 ms |
| 32 caracteres | 273 ms |
| 64 caracteres | 843 ms |
| 128 caracteres | 3.621 ms |
Hasta aquí, normal. El problema estaba en cuántas veces lo lanzábamos.
El campo tenía enganchados dos detectores distintos, input y keyup. Una
tecla normal dispara los dos. Así que cada vez que pulsabas una letra, el análisis
completo corría dos veces: 90 ms en una contraseña de 16 caracteres, medio
segundo en una de 32.
Y no había nada que lo frenara: ni un temporizador, ni un límite de longitud, ni un hilo aparte. A partir de unos veinte caracteres, el navegador tardaba más en analizar de lo que tú tardabas en pulsar la siguiente tecla. Las pulsaciones se acumulaban en una cola que ya no se vaciaba nunca, y la página dejaba de responder mientras escribías. Pegar una contraseña larga la congelaba varios segundos.
El arreglo son dos cambios pequeños. Quitamos el detector de keyup, porque
input ya cubre teclear, pegar, borrar y el autocompletado del gestor: la mitad
del trabajo desaparece sin cambiar absolutamente nada de lo que ves. Y añadimos
una espera de 150 milisegundos: mientras escribes no se analiza nada, y se
analiza en cuanto paras. Nadie teclea tan despacio como para notarlo.
El resultado es idéntico. Barcelona1992$ sigue diciendo lo mismo: que
«barcelona» está en el diccionario, que 1992 parece un año, y que cae en menos de
un segundo.
La descripción estaba cortada a mitad de frase en quince idiomas
Esta es más tonta y más vergonzosa.
La frase que aparece bajo el título en el buscador —la meta description— estaba truncada en quince de los dieciocho idiomas del comprobador. Solo se salvaban el español, el coreano y el japonés. Alguien la recortó por longitud en algún momento, cortó a mitad de palabra y nadie lo miró después.
En tres idiomas el corte cayó justo en medio de un carácter especial, así que lo que se publicaba en Google era esto:
| idioma | lo que servíamos | lo que debía decir |
|---|---|---|
| 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 |
Lo llamativo es dónde estaba: en la página que mejor funciona de todo el sitio. El comprobador convierte muchísimo mejor que el generador, y lo hacía con la descripción rota. Están completadas las quince.
De paso, en coreano, japonés y vietnamita hemos movido la marca del principio al final del título. En el buscador el dominio ya se ve aparte, así que empezar por «password.es ·» solo gastaba el espacio que más pesa.
Un sesgo de uno entre cien millones
El generador elige cada carácter con crypto.getRandomValues(), que es la fuente
de azar buena del navegador. Pero para convertir ese número enorme en «una
posición del alfabeto» hacíamos una división con resto, y ahí hay una trampa
clásica: 2³² no es múltiplo de 83, así que las primeras posiciones del alfabeto
salían un pelín más a menudo que las últimas.
Cuánto es «un pelín»: con un alfabeto de hasta 89 caracteres, del orden de una parte en cien millones. No cambia nada. No hace tu contraseña más débil de forma apreciable ni de lejos.
Lo hemos arreglado igualmente, y son tres líneas: se descartan los 45 valores sobrantes de los 4.294.967.296 posibles y se vuelve a sortear. En un sitio sobre contraseñas, «es despreciable» no es una buena razón para dejar un sesgo puesto cuando quitarlo cuesta eso.
Lo que faltaba: que el navegador hiciera cumplir la promesa
Llevamos un artículo entero explicando que tu contraseña no sale de aquí. Era verdad, y aun así era solo una frase nuestra: nada impedía técnicamente que un script inyectado hiciera otra cosa.
Ahora cada página lleva una política de seguridad de contenido. Las dos partes que importan:
- No se ejecuta ningún script que no estuviera en la página al construirla. Cada guion legítimo va firmado con su huella; uno inyectado no coincide y el navegador se niega a ejecutarlo.
connect-src 'none'. El sitio no hace ni una sola petición de red desde JavaScript, y ahora eso lo impone el navegador. Si algún día algo intentara mandar a alguna parte lo que escribes, no saldría.
La promesa dejó de ser una declaración y pasó a ser una regla.
Lo que sigue sin estar bien
Actualización del 31 de agosto. Las tres cosas de esta sección se arreglaron el mismo día en que se publicó este artículo: los quince idiomas ya describen el motor real, las dos escalas son una, y el FAQ del comprobador explica lo de los símbolos. Se dejan escritas porque el registro de lo que estuvo mal vale más que la foto de un sitio impecable.
Aquí es donde este artículo se gana el sitio.
Quince idiomas siguen describiendo el comprobador como el motor antiguo. El
texto de esas páginas dice que reproduce la lógica clásica de PasswordMeter. Ya
no: ese motor se cambió porque daba «muy fuerte» a Contraseña1! y suspendía una
frase larga de cinco palabras, que es exactamente al revés de lo que hay que
decir. El español, el coreano y el japonés están actualizados; los otros quince,
no.
Hay dos escalas distintas en la misma casa. La portada decide si una contraseña es fuerte por sus bits; el comprobador lo decide por el tiempo que costaría romperla. Son criterios distintos y en ningún sitio lo avisamos.
El generador y el comprobador no cuentan los mismos símbolos: uno usa 27, el otro supone 33. La diferencia es pequeña, pero está ahí.
Ninguna de las tres es un fallo grave. Las tres son deuda, y prefieren estar escritas aquí que esperando a que las encuentre otro.
El registro de esta versión
Como el repositorio no es público, el registro de cambios va aquí entero. Versión 0.2.0, del 31 de agosto de 2026:
Añadido. Política de seguridad de contenido por página, con las huellas de cada guion. El artículo sobre dónde están tus contraseñas guardadas, en los dieciocho idiomas. Una cola editorial que decide qué se escribe, y que manda no publicar nada si se queda vacía.
Corregido. La descripción del comprobador, cortada a mitad de frase en quince idiomas, tres de ellos con un carácter partido por la mitad. El bloqueo de la pestaña al teclear. El sesgo del sorteo. Y la foto que faltaba en el artículo anterior.
Cambiado. El título del comprobador en coreano, japonés y vietnamita. El despliegue, que ahora se dispara cuando el sitio construido ya existe y no un minuto antes. Y las traducciones al vietnamita, hindi y árabe, que dejan de bloquear una publicación aunque sigan siendo las más flojas.
Las cifras de este artículo están medidas, no estimadas: los tiempos de zxcvbn con el mismo paquete que sirve el sitio y contraseñas con palabras y sustituciones; el sesgo del sorteo, calculado sobre los 4.294.967.296 valores de un entero de 32 bits. El motor del comprobador es zxcvbn, de código abierto.
Foto de Ernandes Alves · Pexels