Antes de cambiar de trabajo, de publicar un sitio nuevo o de «ponerle un signo de exclamación» a una contraseña vieja, mucha gente busca si esa cadena ya circula. En los resultados, «comprobar si mi contraseña es segura», «Have I Been Pwned» y «consulta de filtraciones online» aparecen juntos y suenan a la misma pregunta. Abres las páginas y los protocolos se separan: unas hacen POST del cuadro de texto a su propio servidor, otras piden a un tercero una lista de sufijos de hash, y otras descargan un diccionario público de contraseñas débiles y comparan en la pestaña. Esas tres rutas dan tres respuestas distintas a «¿salió la contraseña de esta página?».
Este artículo no recita una barra Débil / Media / Fuerte, y no enseña a atacar la base de nadie. La pregunta es más estrecha: qué puede demostrar una lista local de contraseñas filtradas, y qué puede demostrar una consulta a un corpus grande, si está bien hecha. La comprobación de fortaleza de MyPassGen es del primer tipo: la candidata no se sube; la página compara con una lista pública de contraseñas débiles que se carga con el sitio; todas las herramientas se abren sin cuenta. El resto del texto marca el límite y enseña a confirmarlo en la pestaña Red de las herramientas para desarrolladores.
Tres formas distintas de «comprobar una contraseña»
Ponle nombre primero a cada protocolo. Un texto de marketing puede decir «local», «no se sube» y «comprobado contra filtraciones» en la misma frase, y apuntar a tres diseños distintos.
| Método | Qué sale del navegador | Pregunta que puede responder |
|---|---|---|
| Entregar la contraseña a un sitio | Texto plano, o un campo de formulario reversible | El otro anfitrión dice que «ya lo miró» — tú no ves la prueba |
| Consulta de rango con k-anonimato (HIBP) | Los 5 primeros caracteres hexadecimales de un hash SHA-1 o NTLM | Si ese hash aparece en el corpus que ellos mantienen |
| Comparación local con una lista pública de débiles | Un archivo estático de diccionario, no tu entrada | Si es una cadena muy abusada, como 123456 o password |
El primer método es el más cómodo y el más difícil de auditar. Una página puede prometer que «borra la consulta al instante». Los registros, las copias de seguridad y los scripts de analytics pueden guardar una copia igual. El segundo es el diseño que Have I Been Pwned documenta para Pwned Passwords: el navegador calcula el hash, manda solo el prefijo a api.pwnedpasswords.com/range/{prefix} y compara los sufijos en local. El tercero no manda ni el prefijo. El diccionario es un conjunto público de contraseñas débiles habituales — de cientos a diez mil filas, no «cada filtración de internet».
El Instituto Nacional de Estándares y Tecnología de EE. UU., en NIST SP 800-63B-4, pide a quien verifica que, al crear o cambiar una contraseña, la contrasten con una lista de valores «de uso común, previsibles o comprometidos», y que no apilen encima reglas obligatorias de mayúscula, minúscula, dígito y símbolo. También dice que el trabajo principal de esa lista negra es bloquear las primeras conjeturas de un ataque online; cuando la lista supera la ventana de limitación de intentos, las filas extra aportan poco. Ahí encaja una lista local de las más usadas: un primer filtro de contraseñas débiles, no una búsqueda en cada archivo de filtración.
Elige la pregunta antes de elegir la herramienta
«¿La probaría primero un diccionario?» y «¿apareció esta cadena en una filtración concreta?» son frases distintas. Una lista local responde la primera. Una consulta de rango a un corpus grande responde la segunda solo para el corpus que la otra parte tiene de verdad. Ninguna sustituye la regla: no reutilices la misma contraseña en varios sitios.
Qué implica entregar el texto plano a un sitio
Siguen existiendo «comprobadores online de contraseñas» que meten la cadena del cuadro de texto en el cuerpo de la petición. Unos llaman al campo JSON password. Otros la dejan en la cadena de consulta. Otros aplican una codificación reversible y hacen POST de eso. Para el navegador, el tráfico se parece a un formulario de inicio de sesión: el anfitrión lejano, el proxy inverso y el registro de acceso pueden ver ese envío.
HTTPS solo corta a quien escucha en el camino. No impide que el otro extremo escriba el texto plano en disco, ni que un script de analytics reenvíe el campo. Lo que intentas reducir es si esta comprobación creó a otra parte que ahora conoce la cadena. Eso no es el trabajo de HTTPS. El artículo anterior, cómo comprobar que el cifrado en el navegador no sube el texto plano, usa la misma regla: el eslogan no demuestra nada; el tráfico, sí.
Hay una forma más discreta de entregarla: poner la candidata en un parámetro de consulta y reenviar la URL a un compañero o pegarla en un ticket. Las cadenas de consulta aterrizan en la línea de petición y en el registro del otro extremo. Algunos recursos de terceros siguen recibiendo ruta y consulta en el Referer. Si la cadena es la contraseña de una cuenta en uso, ese paso eres tú difundiendo. El valor por defecto seguro es: una contraseña real se queda en el cuadro de texto de esta pestaña. No la escribas en una URL, y no la pegues en un «comprobador» que sube el original.
Una consulta de corpus completo que solo manda un prefijo
La API de rango de Have I Been Pwned separa «buscar en un corpus grande» de «entregar el original». Los pasos documentados son: codificar la contraseña en UTF-8, calcular SHA-1 (también ofrecen NTLM), tomar los cinco primeros caracteres hexadecimales y pedir GET https://api.pwnedpasswords.com/range/{prefijo}. La respuesta es una lista de sufijos y recuentos, separados por dos puntos. El cliente vuelve a unir prefijo y sufijo en el dispositivo y busca una coincidencia completa. Troy Hunt describe esto como k-anonimato en Understanding Have I Been Pwned's Use of SHA-1 and k-Anonymity: el servidor ve un cubo de hash, no el hash completo, y no la contraseña.
Cuando Cloudflare publicó el diseño con HIBP, dio cifras que aún puedes contrastar con el texto: con un prefijo de 5 caracteres, el cubo mediano tenía unos 305 hashes y la respuesta mediana unos 12,2 KB. La API también ofrece Add-Padding: true, que rellena cada respuesta hasta unas 800–1.000 líneas para que un observador no infiera «esta era una contraseña muy común» solo por la longitud. Todo eso hace que una consulta de rango sea mucho más contenida que un POST de texto plano — y sigue siendo una petición de salida. En Red verás una llamada a api.pwnedpasswords.com. Si cortas la red, este tipo de consulta debería fallar.
Una consulta de rango tampoco es «anonimato perfecto». El prefijo le dice a un observador en cuál de los 165 cubos cayó tu hash. Si el script de la página copia el original antes de mandar el prefijo, el k-anonimato no ayuda. Buscar un correo y buscar una contraseña tampoco son la misma API: HIBP v3 usa un prefijo de 6 caracteres para consultas de rango de correo hasheado, y eso es otra superficie de producto. Este artículo solo compara «¿aparece esta contraseña en un corpus de contraseñas?». No trata las suscripciones de buzón ni el monitoreo de dominio como la misma comprobación.
Por eso, «usamos HIBP» no es la misma frase que «la contraseña no salió del dispositivo». La versión precisa es: el original y el hash completo no se envían, por diseño; un prefijo y una petición de rango sí salen. Si aceptas que «un tercero que mantiene el corpus se entere del cubo de hash», es un compromiso de ingeniería razonable. Si exiges que «esta comprobación no mande ni un prefijo», usa la lista local de la siguiente sección y acepta una cobertura mucho más estrecha.
La lista local solo baja un diccionario, no entrega la contraseña
Una comparación local va al revés: descarga una lista pública de contraseñas débiles al origen actual y hace una búsqueda de conjunto en el script. En Red puede aparecer el diccionario. No debe aparecer la candidata del cuadro de texto. La lista en sí es dato público. Una fuente típica es un archivo «top N de diez millones de contraseñas» en SecLists, mantenido en torno a la colección de OWASP / Daniel Miessler. Responde «¿la probaría primero el diccionario de un atacante?», no «¿está en alguna filtración inédita?».
La comprobación de fortaleza de MyPassGen sigue ese límite. Al abrir la página pide data/leaked-top10k.txt: unas 860 líneas, una contraseña en minúsculas por línea, empezando por cadenas como 123456, password y qwerty. La coincidencia ocurre en el navegador: primero minúsculas, luego un juego corto de variantes — tratar @ / 4 como a, 0 como o y leet parecido, más quitar de uno a tres dígitos finales — y después consultar el conjunto. Un acierto se marca Débil aunque la cadena parezca «larga». Si el diccionario no carga, el script cae a un conjunto mínimo interno (password, 123456 y unas pocas más). No cambia a una API externa de filtraciones.
La barra de fortaleza es un segundo cálculo local. El conjunto de caracteres suma 26 + 26 + 10 + 32 según haya minúsculas, mayúsculas, dígitos y símbolos. La entropía es, a groso modo, longitud por log2(conjunto), y se descuenta si se repiten demasiados caracteres. Los umbrales son: por debajo de unos 40 bits, Débil; por debajo de 60, Media; por debajo de 80, Fuerte; 80 o más, Muy fuerte. Menos de 8 caracteres recibe su propio aviso de «demasiado corta». El generador aleatorio admite 6–128 caracteres y por defecto usa 16. La fuerza bruta sin conexión se estima en 1010 conjeturas por segundo; la limitación online, en 103 — órdenes de magnitud para leer, no una promesa sobre una GPU concreta. Los eventos de analytics registran el grado y si hubo acierto en la lista. No envían la contraseña.
Esas cifras las puedes contrastar en esta máquina: cuenta las líneas del diccionario en un editor o con wc -l. En Red debería verse el diccionario y no debería verse la entrada. Eso sigue sin poder escribirse como «buscamos en toda la red». Unas 860 filas no cubren ni el Top 10.000 público de SecLists, y menos un corpus indexado por hash del tamaño del de HIBP. La única conclusión honesta de un fallo es: no es una contraseña débil habitual de esta lista.
Un fallo no es «segura» ni «nunca se filtró»
Una lista local corta la cabecera de un diccionario. Tu contraseña puede estar en una filtración fuera de la lista, en un combo de relleno de credenciales o en conjeturas dirigidas a tu sitio. Cuando necesites una nueva, genérala en este dispositivo. No conserves la palabra vieja y le añadas el año o un signo de exclamación.
La barra de fortaleza no demuestra que no se filtró
Una barra de fortaleza estima el espacio de búsqueda. No busca en un archivo. Una contraseña aleatoria de 20 caracteres puede tener mucha entropía y existir ya en el archivo de filtración de otra persona. El atacante no recorrerá el alfabeto desde el principio; usará la lista hecha. Al revés, Password1! suele cumplir un formulario de «mayúscula, minúscula, dígito y símbolo» y casi siempre está en una lista pública de débiles. Ese patrón de reutilización es la razón por la que el NIST dejó las reglas de composición.
Si una página muestra a la vez un grado de fortaleza y un resultado de lista, la lista debe mandar sobre la barra: un acierto es Débil. La barra sigue siendo útil. Señala «demasiado corta», «solo una clase de caracteres» o una racha de teclado tipo qwerty. Por sí sola no puede emitir un certificado de «sigue usándola». La decisión que sueles necesitar son dos frases: acierta la lista, o tiene menos de 8 — cámbiala ya; falla la lista y es suficientemente larga — aun así no la reutilices entre sitios, y escribe una cadena nueva para las cuentas importantes con un gestor de contraseñas o el generador local.
«Una consulta a toda la red dijo que no coincidía» tampoco es el final. Una consulta de rango depende de lo que el otro corpus haya ingerido y de con qué frecuencia se actualiza. Filtraciones inéditas, contraseñas de sistemas internos y variantes que aún no se han hasheado en ese conjunto no aparecen. Es mucho más ancha que una lista local de 860 filas, y sigue siendo la muestra de otra persona. Usar las dos herramientas está bien si sabes qué mandó cada una hacia fuera y qué significa un fallo.
Compruébalo en Red: el diccionario puede aparecer, la contraseña no
Los pasos de abajo no dependen de una promesa de marca. Usa una contraseña de prueba desechable — password, o una cadena temporal que no hayas usado en ninguna cuenta. No pegues una contraseña en uso en una demostración.
- Abre la pestaña Red de las herramientas para desarrolladores y activa Conservar registro / Preserve log. Filtra primero Fetch / XHR y luego recorre documentos y el resto de peticiones.
- Recarga la página de comprobación. Deberías ver una lista estática (en este sitio,
leaked-top10k.txt). Abre esa petición: la respuesta es una contraseña por línea y el cuerpo de la petición debería ir vacío. - Escribe la contraseña de prueba en el cuadro y espera el resultado. Revisa las peticiones nuevas: la URL, la consulta, el JSON y los campos de formulario no deben contener la cadena que acabas de teclear.
- Busca en el panel
pwnedpasswords,hibpyrange/. Un diseño de lista local no debería tocar esos anfitriones. Si lo hace, la página lanzó una consulta de rango: lee la sección anterior en vez de tratarla como «totalmente local». - Revisa las peticiones de analytics (las rutas suelen incluir
matomoocollect). Los nombres de evento pueden decir Débil / Media / Fuerte. Los valores no deben incluir la contraseña. - Para comparar un diseño de corpus grande, prueba la misma contraseña desechable en una página que llame a HIBP. Deberías ver un GET a
api.pwnedpasswords.com/range/cuya ruta sean cinco caracteres hexadecimales y nada más.
Corta la red y escribe otra vez. Es una comprobación extra útil para un diseño local: si el diccionario ya está en caché, la fortaleza y los aciertos de lista deberían seguir calculándose; una consulta de rango debería fallar. No trates «cero peticiones» como la única nota de aprobado — la primera visita tiene que bajar el diccionario, y eso no es el mismo tráfico que un POST de la contraseña. El artículo anterior usó el mismo panel para el cifrado local. Aquí miras una cosa más: si alguna petición de negocio lleva tu entrada.
Errores frecuentes: barra verde, «toda la red» y «ya lo comprobé»
«La barra está verde, así que no se ha filtrado» no se sostiene. El verde describe el espacio de caracteres. Una filtración describe si otra persona ya tiene la misma cadena. Las dos cosas pueden ser ciertas a la vez.
«Dice cálculo local, así que no salió nada de la pestaña» tampoco se sostiene. Una lista local descarga un diccionario. Una consulta de rango descarga un cubo de hash. Lo que quieres prohibir es que el original —y el hash completo— salgan como dato de negocio. No hace falta prohibir cada petición HTTP.
«No apareció en HIBP, así que la puedo reutilizar en todos los sitios» es el error caro. El relleno de credenciales (credential stuffing) prueba una contraseña contra muchos sitios. No exige que esa contraseña esté en el top mil público. Ni una lista local ni una consulta de corpus grande arreglan la reutilización. Genera una contraseña nueva en este dispositivo, usa el valor aleatorio por defecto de 16 caracteres o más, y guarda una cadena distinta por sitio.
Pegar una contraseña en el chat para que un compañero «vea si es fuerte» convierte una comprobación en una filtración. Cuando tengas que entregar una contraseña nueva a otra persona, pon un secreto corto en un enlace de un solo uso y deja la clave detrás de # en la URL. Un archivo que vas a descifrar más de una vez va en la caja de cifrado de archivos. La página de comprobación responde «mira tú la lista y la barra». No es un canal de intercambio de claves.
Por dónde empezar
Empieza con una contraseña que ya pienses retirar, o con una que nunca hayas usado en una cuenta real. Abre la página de comprobación, mira la petición del diccionario en Red, escribe y confirma que la cadena no salió. Si acierta la lista, no te quedes con dos caracteres y la reutilices. Abre el generador de contraseñas y crea una en este dispositivo, de longitud 16 o más. Un fallo solo significa que no es miembro de este conjunto público de débiles. Aun así, guarda una contraseña distinta por sitio.
Si la pregunta que de verdad tienes es «¿ha aparecido esta contraseña en una filtración masiva conocida?», unas 860 filas locales no bastan. Usa una herramienta que haga una consulta de rango con k-anonimato y confirma en Red que solo salió un prefijo de 5 caracteres. No entregues el original a una página de consulta desconocida. Tras las dos comprobaciones, recuerda: una herramienta que se abre sin registro no sustituye la protección de inicio de sesión de cada sitio, y no puede demostrar que un servidor no vaya a filtrar más adelante.
Cuando hayas hecho eso, ya puedes responder al título. Una lista local de contraseñas filtradas demuestra «¿se parece al lote que los atacantes prueban primero?». Una consulta de contraseñas a un corpus grande —si está bien implementada— demuestra «¿aparece el hash completo en el corpus que ellos mantienen?». La primera saca un diccionario y deja la contraseña dentro. La segunda saca un prefijo y deja el original dentro. Un tercer diseño que hace POST del original no pertenece a ninguno de los dos.
Preguntas frecuentes
Si la lista local falla, ¿sigo teniendo que consultar Have I Been Pwned?
Depende de qué frase necesites. Un fallo solo significa que la cadena no está en esta lista pública de débiles. Si también quieres saber si aparece en el corpus de hashes de contraseñas de HIBP, haz una consulta de rango aparte y confirma en Red que solo salió un prefijo de 5 caracteres. Mantén las dos comprobaciones separadas. No las comprimas en «ya busqué en toda la red».
¿Una consulta de rango le dice a HIBP mi contraseña?
Según el diseño oficial y el texto de Troy Hunt, la otra parte recibe los cinco primeros caracteres de un hash SHA-1 o NTLM — no la contraseña, y no el hash completo. La coincidencia termina en tu navegador. Sigue siendo una petición de salida. Si no vas a dejar que salga ningún prefijo del dispositivo, usa solo la lista local y acepta la cobertura más estrecha.
¿Hace falta una cuenta para comprobar una contraseña? ¿Se sube la candidata?
No hace falta cuenta. En un diseño local, la candidata debería quedarse en el cuadro de texto. Lo que puede salir es el archivo de diccionario, más eventos de analytics que no contienen el original. Si una página lo hace de verdad es una pregunta de Red, no una línea de «nunca subimos nada» en la página.
¿Me puedo fiar del «tiempo de descifrado sin conexión: N años» de la barra?
Esa cifra es una pista de orden de magnitud a una tasa de conjetura fija. No es una medición de una GPU concreta ni de un ataque por diccionario. Cuando la lista acierta, el atacante no va a seguir ese reloj. Trátalo como un recordatorio de que la cadena es corta o usa demasiado pocas clases de caracteres — no como una garantía de seguridad.