El hashing de contraseñas es esencial para mantener la seguridad de los datos en una base de datos. Este proceso transforma una contraseña en una secuencia irreconocible mediante algoritmos de cifrado. Esto no solo protege la información si alguien accede a la base de datos, sino que también garantiza que ni siquiera los administradores puedan ver las contraseñas reales de los usuarios.
¿Por qué es importante el hashing?
Protección de datos: Impide que atacantes obtengan contraseñas directamente de la base de datos.
Privacidad del usuario: Asegura que ni el administrador ni otras personas vean las contraseñas.
Seguridad adicional: Evita que contraseñas débiles, como '123456', sean fácilmente explotadas.
¿Cómo implementar hashing en NodeJS?
Para implementar correctamente el hashing de contraseñas en un proyecto en NodeJS, es necesario seguir ciertos pasos y utilizar las herramientas adecuadas.
Paso 1: Instalación de la librería de hashing
Utiliza una librería de confianza específicamente diseñada para NodeJS. Asegúrate de instalar también el tipado, ya que muchas librerías no lo incluyen por defecto.
Una vez instalada la librería, debes integrarla en el servicio donde se gestionan las credenciales del usuario.
import*as bcryptfrom'bcrypt';asyncfunctioncreateUser({ email, password }){// Obtener y generar un hash de la contraseñaconst hashedPassword =await bcrypt.hash(password,10);// Guardar el usuario con la contraseña hasheadasaveUserToDatabase({ email, password: hashedPassword });}
El proceso de hashing es asíncrono y por eso es importante manejarlo dentro de una función async. Normalmente se utilizan 10 saltos (rondas) para incrementar la complejidad del hashing.
Paso 3: Excluir contraseñas del retorno de consultas
Es importante que las contraseñas no se devuelvan en las respuestas de las API. Usa serialización y otras técnicas para asegurarte de que las contraseñas estén escondidas.
classUserTransformer{// Decorador para excluir el campo 'password'@Exclude() password:string;}
¿Cómo verificar un usuario con autenticación?
Además del hashing, es vital contar con un mecanismo de búsqueda eficiente para autenticar a los usuarios. Crear un método para buscar por email es crucial.
El proceso de hashing en MongoDB se mantiene similar al de otros sistemas de gestión de bases de datos. La implementación varía dependiendo del ORM o la herramienta que estés utilizando, pero el concepto sigue siendo el mismo: proteger la información de usuario mediante métodos de cifrado robustos.
Siempre mantén tus conocimientos al día y recuerda que la seguridad es un aspecto crucial del desarrollo de software. Con dotarte de estas herramientas y prácticas, brindas a tus usuarios la protección que merecen.
Hashing de Contraseñas en Bases de Datos con Node.js
Pienso que usar un Exclude es mejor porque indiferentemente de donde mandas a llamar los usuarios ya te vienen sin la contraseña, en cambio de este modo siempre tendrás que indicar que te traía los campos y no la contraseña
También que este ejemplo son solo 3 campos, pero supongamos que tu entidad de usuario tiene 10 campos, vas a tener que escribir 9 solo para sacar 1
Para los que están usando Mongoose y quieren eliminar el password de la respuesta pueden instalar el paquete:
npm i nestjs-mongoose-exclude luego en su Entity utilizar el decorador @ExcludeProperty() y por último utilizar un Interceptor a nivel de ruta o del controlador completo
quedaría así:
Para poder entender de una manera mas simple el hash, la particularidad de este método de seguridad es que el Hash en si no se desencripta una vez ha sido encriptado. Simplemente se compara el código (o password) ingresado al momento de iniciar sesión con el hash almacenado en la base de datos.
Los pipe son clases que se ejecutan en los argumentos de nuestros controladores y el hashing de contraseña tiene que ser algo que se haga justo antes de la creación del usuarios ya que si en nuestro servicio tenemos otros tipos de validaciones y alguna no pasa pues de nada nos sirve consumir recursos en el hashing si igual no lo usaramos
por eso pienso que sería algo que se haría justo antes del guardado, que ya todo lo que se este validando haya pasado correctamente
En caso de que alguien tenga preocupaciones de seguridad a la hora de traer el usuario con contraseña del DB ( en ocasiones es necesario), con typeORM se puede añadir el atributo “select” en la petición findOne y traer solo los atributos necesarios
const user =awaitthis.userRepo.findOne({where:{ id },select:["username","email","role"]});
Hola!,
Estoy teniendo problemas al aplicar el exclude(), lo agrego a mi entidad pero no se está excluyendo.
Esta es mi entidad.
@Get(':id')getOne( @Res() res:Response, @Param('id',ParseIntPipe) userId: number,){this.userService.getOne(userId).then((response:User)=>{return res.status(HttpStatus.OK).json({"statusCode":HttpStatus.OK,"message":"Usuarios recuperados con éxito","user": response,});}).catch(response=>{return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({"statusCode":HttpStatus.INTERNAL_SERVER_ERROR,"message":"Error en el servidor","error":"Error en el servidor"});});}@Get()getMany(@Res() res:Response){this.userService.getMany().then((response:User[])=>{return res.status(HttpStatus.OK).json({"statusCode":HttpStatus.OK,"message":"Usuarios recuperados con éxito","users": response
});}).catch(response=>{return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({"statusCode":HttpStatus.INTERNAL_SERVER_ERROR,"message":"Error en el servidor","error":"Error en el servidor"});});}
y este es el servicio
asyncgetOne(idUser: number):Promise<UserDto>{const user =awaitthis.userService.findOne({where:{iduser: idUser
}}); user.apps=awaitthis.appUserService.find({select:['idapp_user'],relations:['application','role'],where:{iduser: user.iduser}});return user;}getMany():Promise<UserDto[]>{returnthis.userService.find();}
Que podría estar haciendo mal?, gracias por su ayuda.