Cómo proteger contraseñas con hashing usando Bcrypt en NestJS

Clase 24 de 35Curso de Backend con NestJS

Resumen

Asegurar la información sensible de los usuarios es una prioridad en cualquier aplicación moderna. Un error frecuente es almacenar el password en texto plano en la base de datos, lo que representa un riesgo significativo para la privacidad y la seguridad de los datos. En este contenido aprenderás por qué y cómo evitarlo utilizando técnicas de hashing con la librería Bcrypt en un entorno NestJS, enfatizando buenas prácticas y recomendaciones prácticas.

¿Por qué es una mala práctica guardar contraseñas en texto plano?

Almacenar contraseñas en crudo en la tabla de usuarios expone esos datos a cualquier persona con acceso a la base de datos, incluso a los dueños o desarrolladores del sistema. Esto contraviene el principio de que solo el usuario debe conocer su contraseña. Nadie más—ni administradores ni desarrolladores—debería verla ni tener acceso a ella.

  • Los passwords expuestos pueden ser robados fácilmente.
  • Protege la privacidad cifrándolos—ni el equipo técnico debe poder revertir el proceso.

¿Cómo aplicar hashing con Bcrypt para proteger passwords en NestJS?

Lo habitual es usar hashing para contraseñas. El sistema utiliza una transformación irreversible donde solo el usuario conoce el dato original. En NestJS, esto se realiza con la librería Bcrypt.

Pasos prácticos:

  1. Consultar la documentación de NestJS, apartado de security, para buenas prácticas de hashing y encryption.
  2. Instalar la librería Bcrypt y su tipo correspondiente para TypeScript.
    • Ejecuta ambas líneas de instalación en la terminal.
  3. Importar Bcrypt en el código.
  4. Definir el número de iteraciones del hash (por defecto es diez, pero puede configurarse vía variable de entorno).
  5. Al recibir el password desde el usuario, crear el hash antes de guardarlo en la base de datos.
    • Ejemplo: el password en texto plano nunca se almacena, solo la versión hasheada.
  6. Uso del método compare en Bcrypt para validar que el password ingresado corresponde con el hash guardado.

¿Cómo automatizar el hashing al guardar usuarios en la base de datos?

Para evitar el error humano, se recomienda usar hooks del ORM (como TypeORM). En particular, el hook before insert permite ejecutar lógica justo antes de almacenar los datos.

  • Ubica la entidad usuario donde está el campo password.
  • Añade el decorador before insert tomado de TypeORM.
  • Dentro del hook, reemplaza el password crudo por el hash.
  • Este proceso debe ser asíncrono para garantizar que el hashing termine antes de guardar.

Consideraciones: - El número de saltos en el hash puede ser constante o leerse de una variable de entorno para ajustarlo según el entorno o nivel de seguridad deseado.

¿Cuál es la diferencia técnica entre save y create al usar hooks?

El método save no ejecuta los hooks before insert por defecto. En cambio, create permite:

  • Generar la estructura del usuario.
  • Ejecutar todos los hooks, como el de hashing password.

Por eso, se recomienda usar create para que la lógica de protección de datos no falle.

  • Una vez creado el ‘new user’, guárdalo con save para que el hash se almacene.
  • Ajusta el nombre de variables para evitar confusiones.

¿Qué hacer con contraseñas antiguas y cómo validar el hash?

Las contraseñas previas seguirán apareciendo en texto plano. Será necesario hacer una migración manual para proteger esos datos con hashing. Para las nuevas, verifica:

  • Al crear usuarios, el password ya es hasheado y al refrescar la base de datos solo aparece el hash.
  • Nadie podrá conocer el password original a partir del hash (a excepción del propio usuario).

¿Cómo evitar mostrar la contraseña (incluso hasheada) al consultar usuarios?

Aunque el hash ya protege el valor original, no se recomienda mostrar el campo password en endpoints y respuestas. El siguiente paso será excluir automáticamente este dato.

Piensa cómo resolverías este reto y comparte tus ideas en los comentarios.