Guardar un hash de contraseña suena correcto, pero usar una función general como SHA-256 directamente crea una falsa seguridad. Si se filtra la base, el atacante no intenta revertir el digest. Hashea contraseñas probables y compara. Los hashes rápidos le permiten probar cantidades enormes. El hashing de contraseñas es diferente porque encarece cada intento.
Después de un robo, el ataque es offline
Un login online puede limitar intentos, detectar abuso y pedir MFA. Una tabla robada elimina esas defensas. El atacante trabaja con su hardware, sin tocar la aplicación. Por eso importan el coste por guess y la imposibilidad de reutilizar cálculos entre usuarios.
Las contraseñas humanas tienen baja entropía relativa. La función one-way no compensa inputs predecibles si cada intento cuesta casi nada.
Salt evita precomputación compartida
Un salt es un valor aleatorio único guardado con cada hash. Dos usuarios con la misma contraseña obtienen resultados distintos. Rainbow tables generales dejan de servir para toda la base.
El salt no necesita ser secreto; necesita ser único y generado bien. Las bibliotecas modernas lo crean y lo codifican automáticamente junto con parámetros.
Los algoritmos de contraseña son costosos a propósito
Argon2, scrypt, bcrypt y PBKDF2 permiten configurar coste. Argon2 y scrypt pueden exigir memoria, reduciendo ventajas de hardware paralelo. La configuración debe mantener login aceptable y aumentar coste para atacantes.
Repetir SHA-256 manualmente no equivale a un algoritmo revisado. Los detalles de construcción importan y las soluciones caseras fallan con frecuencia.
Los parámetros deben evolucionar
El hardware mejora. Un hash guardado debe incluir algoritmo y parámetros para verificar valores antiguos y rehashear después de un login exitoso. Así el sistema migra gradualmente sin pedir reset masivo.
Las APIs de plataforma suelen ofrecer funciones para saber si un hash necesita rehash. Usarlas evita formatos propios difíciles de mantener.
Los parámetros se miden en hardware real
Copiar una configuración de otro proyecto es arriesgado. El equipo debe medir duración de login, concurrencia esperada y margen de CPU o memoria en su propia infraestructura. Costes demasiado bajos ayudan al atacante; costes excesivos pueden facilitar denial of service.
Revisar parámetros periódicamente permite subir dificultad sin sorprender a usuarios. La seguridad de contraseñas es una propiedad que envejece junto con el hardware.
La normalización de entrada debe ser estable
Contraseñas con espacios, acentos o caracteres compuestos deben convertirse al mismo conjunto de bytes durante registro y login. Cambiar reglas de trimming, Unicode normalization o encoding puede bloquear usuarios legítimos. La aplicación no debe “arreglar” secretos de forma oculta después de que fueron creados.
Si se aplican reglas de normalización, deben documentarse y probarse. Muchas veces lo más seguro es preservar exactamente lo que el usuario envía por el canal definido, sin transformaciones inesperadas.
Las cuentas privilegiadas merecen el mismo tratamiento
Administradores, cuentas de servicio y usuarios internos no deberían quedar fuera del sistema de hashing porque se crean manualmente. De hecho, suelen tener mayor impacto si se comprometen. Sus credenciales necesitan los mismos algoritmos, rotación planificada, MFA y revisión de exposición en scripts o variables de entorno.
Un password hash fuerte no compensa una contraseña compartida entre entornos o pegada en un archivo de despliegue. El almacenamiento seguro es una capa dentro de una política completa de credenciales.
Pepper añade una defensa separada
Algunos sistemas agregan un secreto del servidor, llamado pepper. Si se filtra solo la base, el atacante no tiene todos los inputs. Ese secreto debe vivir en un gestor de secretos y tener plan de rotación.
Pepper no reemplaza salt ni algoritmo fuerte. También añade riesgo operativo: perderlo puede impedir verificar contraseñas.
Las contraseñas no deben ser recuperables
Si un servicio puede enviar la contraseña actual por correo, la almacena de forma reversible o en texto claro. Un sistema seguro solo verifica la contraseña enviada y usa reset tokens cuando se olvida.
Los reset tokens deben ser aleatorios, cortos de vida, de un solo uso y almacenados con cuidado. Logs y analytics nunca deben capturar contraseñas.
La verificación no debe revelar diferencias útiles
Mensajes y tiempos no deberían permitir enumerar usuarios. Muchos sistemas ejecutan un hash representativo incluso para cuentas inexistentes y devuelven una respuesta neutral. Rate limiting debe equilibrar seguridad y disponibilidad.
La comparación debe usar la función de verificación de la biblioteca. Reimplementar parsing o igualdad abre riesgos de timing y compatibilidad.
Un buen hash compra tiempo, no invulnerabilidad
Después de un breach, la organización aún debe evaluar parámetros, invalidar sesiones, forzar resets si procede y avisar con claridad. MFA, passkeys, gestores y detección de contraseñas filtradas añaden capas.
Cambiar una contraseña también debería cerrar sesiones antiguas y tokens de recuperación pendientes cuando el riesgo lo exige. De lo contrario, el secreto nuevo convive con credenciales secundarias comprometidas.
El modelo correcto es simple: hashes rápidos identifican datos; password hashes defienden contra guessing. Usa una API mantenida, parámetros modernos, salt único y plan de actualización.