En una auditoría a una pyme encontramos la contraseña del NVR pegada en un post-it: "P@ssw0rd!". El encargado de TI estaba tranquilo — tenía mayúscula, número y símbolo, "cumplía la política". La probamos contra un diccionario de claves filtradas y cayó antes del primer sorbo de café: figura en todas las listas del planeta. Mientras tanto, "caballo correcto batería grapa" — que parece chiste — habría aguantado más que la empresa. La diferencia entre ambas no es opinión ni magia: es aritmética, y al final de esta guía la vas a poder hacer de memoria.
Entropía: la fuerza es largo × log₂(alfabeto)
Un atacante no "lee" tu contraseña: la adivina probando combinaciones. La fuerza de una clave es, literalmente, el tamaño del pajar donde está escondida. Ese tamaño se mide en bits de entropía, y la fórmula cabe en una servilleta: entropía = largo × log₂(tamaño del alfabeto). Cada bit adicional duplica las combinaciones que hay que probar.
Piensa en un candado de bicicleta: agregar símbolos raros es hacer cada rueda un poco más grande; agregar caracteres es agregar ruedas completas. Una minúscula aporta log₂(26) = 4,70 bits; un carácter sacado de las cuatro clases (94 símbolos ASCII imprimibles) aporta 6,55. La diferencia por carácter es pequeña — la diferencia por largo es enorme, porque el largo multiplica.
¿Y "P@ssw0rd!"? En teoría, 9 caracteres × 6,55 = 59 bits. Pero la fórmula asume que cada carácter se eligió al azar, y ahí está la trampa: "P@ssw0rd!" es la palabra "password" con las mutaciones a→@ y o→0 que toda herramienta de cracking prueba primero, por regla. Su entropía real es un puñado de bits: está a un par de millones de intentos del inicio de la fila, no a 2⁵⁹. Una passphrase hace lo contrario: elige palabras al azar de la lista EFF de 7776 palabras, y cada palabra vale log₂(7776) = 12,92 bits aunque se lea como cuento infantil.
| Alfabeto | Tamaño | Bits por unidad |
|---|---|---|
| solo minúsculas | 26 | 4,70 / carácter |
| + mayúsculas | 52 | 5,70 / carácter |
| + dígitos | 62 | 5,95 / carácter |
| + símbolos (ASCII imprimible) | 94 | 6,55 / carácter |
| palabra al azar (lista EFF) | 7776 | 12,92 / palabra |
El ejemplo con números: tu clave contra una GPU
Escenario realista: a un servicio se le filtró la base de datos y las claves estaban con hash rápido (SHA-256 sin sal ni estiramiento — pasa más de lo que crees). Una sola GPU de escritorio prueba del orden de 10¹⁰ hashes por segundo, y en promedio encuentra la clave al recorrer la mitad del espacio. Hagamos la cuenta completa:
- La fórmula: entropía = largo × log₂(alfabeto). Para 8 minúsculas: 8 × log₂(26) = 8 × 4,70 = 37,6 bits, es decir 26⁸ ≈ 2,09 × 10¹¹ combinaciones.
- Tiempo promedio = (2^bits ÷ 2) ÷ tasa. Con 10¹⁰ intentos/s: 2,09 × 10¹¹ ÷ 2 ÷ 10¹⁰ ≈ 10,4 segundos. Tu clave de 8 minúsculas dura menos que ir a buscar café.
- Sube a 12 caracteres con 4 clases (pool 94): 12 × 6,55 = 78,7 bits → 94¹² ≈ 4,76 × 10²³ combinaciones. Promedio: 2,38 × 10¹³ segundos ≈ 754.000 años. La misma GPU, el mismo ataque.
- La passphrase: 4 palabras EFF al azar = 4 × 12,92 = 51,7 bits → ≈ 2,1 días contra hash rápido. Justa. Con 6 palabras: 77,5 bits → ≈ 350.000 años, y encima se memoriza caminando al auto.
- Moraleja: de 4 a 6 palabras el trabajo del atacante crece 7776² ≈ 60 millones de veces. La entropía no suma — multiplica.
Dos matices honestos. Primero, esto es un ataque offline contra hash rápido: si el servicio guardó bcrypt o scrypt, la tasa se desploma a unos 10⁴ intentos/s y las mismas 8 minúsculas pasan de 10 segundos a unos 4 meses (121 días). Segundo, un ataque online contra un login con límite de intentos es órdenes de magnitud más lento todavía. Puedes jugar con políticas, tasas y escenarios en la calculadora de entropía y tiempo de quiebre.
El gestor de contraseñas: la conclusión lógica
Sigamos la matemática hasta el final. Necesitas claves únicas por servicio — porque cuando se filtra el foro de aeromodelismo donde te registraste en 2019, lo primero que hacen los atacantes es probar ese mismo correo y clave en tu banco, tu VPN y tu correo corporativo (se llama credential stuffing y es el ataque más rentable que existe). Y necesitas que cada una tenga 75+ bits. Nadie memoriza ochenta cadenas aleatorias de 12 caracteres: la aritmética solo deja una salida.
Esa salida es el gestor de contraseñas: una sola clave maestra tipo passphrase de 6 palabras (77,5 bits, memorizable, no está escrita en ninguna parte) y todo lo demás generado por máquina — 20 caracteres, únicos, que jamás intentas recordar ni teclear. El gestor no es una comodidad: es la única arquitectura donde la fórmula cierra. Y donde el servicio lo permita, segundo factor encima.
Hash: huella digital, no cifrado
Cambio de tema, mismo espíritu numérico. Un hash es una función unidireccional: entra cualquier cosa — una letra, un firmware de 2 GB — y sale una huella de largo fijo. Como la huella dactilar: te identifica sin permitir reconstruirte. Aquí está el error conceptual más repetido del rubro: hash no es cifrado. Lo cifrado se descifra con la clave; el hash no tiene puerta de vuelta — no existe "deshashear". Y tiene efecto avalancha: cambia una letra de la entrada y la huella cambia completa.
Uso 1: verificar integridad. Bajaste un firmware y el fabricante publica su SHA-256: si tu hash calza, el archivo llegó intacto y nadie lo tocó en el camino. Se ve así (y sí, una letra distinta habría dado una huella irreconocible):
$ echo -n "redzilla" | md5sum e9b5a2402e7ab94f63d139974709317a - $ echo -n "redzilla" | sha256sum bcff34d1effbe914707d30410323f9ead560f3f610c8aa6aa710f95993551d15 -
Uso 2: guardar contraseñas. Un servicio bien hecho nunca almacena tu clave: guarda su hash, con dos condiciones. Una sal única por usuario — un valor aleatorio que se mezcla con la clave antes de hashear, para que dos usuarios con la misma clave no compartan hash y las tablas precalculadas no sirvan. Y un algoritmo lento a propósito: bcrypt, scrypt o Argon2 hacen miles de iteraciones justamente para que la GPU del ejemplo baje de 10¹⁰ a 10⁴ intentos por segundo. MD5 y SHA-1 son lo contrario: diseñados en los 90 para ser rápidos, que es exactamente lo que no quieres frente a un atacante.
Bonus de terreno: los hashes se identifican a ojo por largo y formato. Practica con el calculador de hash y el identificador de hash:
| Se ve así | Formato | Probablemente es |
|---|---|---|
| e9b5a2402e7ab94f… | 32 hex | MD5 |
| 8581bd83aafb4d6d… | 40 hex | SHA-1 |
| bcff34d1effbe914… | 64 hex | SHA-256 |
| $2b$12$N9qo8uLO… | empieza con $2b$ | bcrypt (trae sal y costo adentro) |
JWT por dentro: carnet firmado, no sobre cerrado
Los tokens JWT mueven la mitad de las sesiones de internet y cargan el mismo malentendido que el hash. Un JWT son tres bloques en Base64URL unidos por puntos: header (algoritmo), payload (los datos: quién eres, cuándo vence) y firma. La analogía correcta es un carnet plastificado: cualquiera que lo tome puede leer tu nombre y tu RUT — el plástico no esconde nada. Lo que hace el holograma (la firma) es delatar si alguien lo alteró.
Compruébalo tú mismo — decodificar el header no requiere ningún secreto, solo deshacer el Base64:
$ echo 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' | base64 -d
{"alg":"HS256","typ":"JWT"} De ahí salen las dos reglas de oro. Uno: jamás metas secretos en el payload — ni claves, ni datos sensibles, ni nada que no le mostrarías al dueño del token, porque él (y cualquier proxy en el camino) lo lee con dos líneas de terminal. Dos: los claims iat (emitido) y exp (vence) van en segundos Unix, y el exp corto no es pesadez del backend: un JWT robado no se puede "revocar" fácilmente, así que su vida útil es tu único freno. Pega cualquier token en el decodificador JWT — corre 100% en tu navegador — y mira qué está declarando por dentro.
Base64, UUID y otros disfraces
Ya viste al culpable de que el payload sea legible: Base64 es codificación, no cifrado. Transforma bytes arbitrarios en 64 caracteres inofensivos para que sobrevivan viajes por correo, JSON o URLs — y cualquiera lo revierte sin clave, pagando de paso un 33% más de tamaño. Escribir en griego no esconde el mensaje de quien habla griego. Si ves un dato "protegido" en Base64, pásalo por el codificador y saluda al texto plano.
Y para cerrar el kit, los UUID en una frase cada uno. UUID v4: 122 bits de azar criptográfico — imposible de adivinar, perfecto como identificador público. UUID v7: antepone el timestamp en milisegundos, así los IDs nacen ordenados cronológicamente y no destrozan los índices de tu base de datos. Genera ambos (y ULID) en el generador de UUID — pero recuerda que un identificador no es una credencial: lo que protege acceso se llama token, y se firma.
Eso es seguridad práctica en tres hábitos: passphrase larga para lo único que memorizas, gestor para todo lo demás, y reflejo inmediato de desconfianza ante todo lo que "parece" cifrado pero solo está codificado. Pasa tu política actual por la calculadora de entropía y abre uno de tus propios tokens en el decodificador JWT: los números convencen más que cualquier charla.