No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Autenticación: cifrar contraseñas para evitar problemas de seguridad

10/29
Recursos

Aportes 35

Preguntas 4

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

"Es el peor de todos los planes"
Ciertamente lo es 😉

el metodo login lo he hecho asi

 async function login(username, password) {
    const data = await store.query(TABLA, {
      username
    });
    const equals = await bcrypt.compare(password, data.password);
    if (!equals) {
      throw new Error('information not valid');
    }
    return auth.sign(data);
  }

No sé si yo me equivoqué en algo, pero en este punto el token se regresa con el password hasheado, algo que se supone que tampoco debería hacerse. Esto es debido a que en dummy, estamos devolviendo el objeto entero que encuentra en “auth”. Por lo que antes de generar el token, se debe eliminar al contraseña.

async function login(username, password) {
  const data = await store.query(TABLE, { username })

  if (await bcrypt.compare(password, data.password)) {
    delete data.password
    return auth.sign(data)
  } else {
    throw new Error('Invalid information')
  }
}

Si alquien tiene inconvenientes al instalar bcrypt (como los tuve yo ) en windows, la solucion es instalar las windows build tools. Tienes 2 opciones, la primera por consola y la segunda descagando un instalador

  1. Abrir powershell con permisos de administrador pegar el siguiente comandonpm install --global --production windows-build-tools
    2- ir al siguiente enlace y descargar el instalador https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools

espero que les sea de ayuda

profe cuando nos subcribimos al jwt no deberia ser mejor quitar la password del payload?

Si tienen problemas para instalar bcrypt en ubuntu, lo que me funciono fue instalar primero node-gyp:

sudo apt-get install node-gyp

y después seguir con la instalación normal:

npm i bcrypt

Creo que simplemente implementado el await de Bcrypt.compare() en la validación es suficiente para obtener el mismo resultado

const login = async (username, password) => {

        const data = await store.query(TABLA, { username })

        if (await bcrypt.compare(password, data.password)) return auth.sign(data);
        else throw new Error('Informacion Invalida');

    }

NUNCA debemos guardar la contraseña como texto plano. Siempre deben estar encriptadas.
Debemos usar librerías de criptografía. Vamos a usar lo que usan los expertos en seguridad: npm i bcrypt.


Ya que hablamos un poco sobre seguridad informática, creo que es un excelente momento para mencionar la ruta de Seguridad Informática

Si bien su enfoque me parece que es para ser un hacerk ético, creo que es importante conocer lo básico para crear programas que sean mucho más seguros.

npm i bcryptjs, por si en algún momento tienen problemas con bcrypt

si tienes problemas con el modulo bcrypt, traten de instalar bcryptjs

Gente yo lo hice así…

    async function login(username, password) {
        const data = await store.query(TABLA, { username: username });
        const pass = await bcrypt.compare(password, data.password)
        if (pass) {
            // Generar token;
            return auth.sign(data);
        } else {
            throw new Error('Informacion invalida');
        }
    }

Minuto 2:13 dice index.html jajaja

Es mas fácil comparar negado así, de ser falso se corta la ejecución y se levanta el error.

// Comparacion de contraseñas con bcrypt
        if (!await bcrypt.compareSync(password, data.password)) {
            throw new Error('Informacion invalida');
       	}

Excelente uso

En el controller de users veo que hay un error ya que creamos la data 2 veces:

    async function upsert(body) {
        const user = {
            name: body.name,
            username: body.username,
        }

        if (body.id) {
            user.id = body.id;
        } else {
            user.id = nanoid();
        }

        if (body.password || body.username) {
            await auth.upsert({
                id: user.id,
                username: user.username,
                password: body.password,
            })
        }

        return store.upsert(TABLA, user);
    }

como podemos ver, despues de la condicional para valdiar que venga el password o el user que creamos la data el usuario vuelve a ser creado

mi solucion fuecolocar un excel y enviar un boom error badRequest:

async function upsert(body) {
        const user = {
            name: body.name,
            username: body.username,
            password: body.password,
        };

        if (body.id) {
            user.id = body.id;
        } else {
            user.id = uuid.v4();
        }

        if (body.password && body.username) {
            await auth.upsert({
              id: user.id,
              username: user.username,
              password: user.password,
            })
        } else {
            throw boom.badRequest('Username and password are required');
        }

Lo resolví de está manera.

Para no usar promesas con bcrypt uso el postfijo Sync y lo hace sincronamente.

Es muy importante cifrar todas las contraseñas para evitar leaks de seguridad.
A pesar de esto, tampoco es buena practica retornar la contraseña encriptada, ni guardarla en el token.
Para eso utilizamos el delete operator antes de retornar la información.

Por ejemplo:

    delete myUser.password;

Si a pesar de utilizar esta linea de código, la contraseña aun esta siendo retornada, pueden re-convertir la propia variable a un objeto, para que el delete operator este disponible.

    myUser = myUser.toObject();
    delete myUser.password;
    return myUser;

Comparto mi solución:

    const login = async (username, password) => {
        const data = await store.query(TABLE, { username: username });

        const areEquals = await bcrypt.compare(password, data.password);

        if (areEquals) {
            // Generate Token
            return auth.sign(data)
        } else {
            throw new Error('Invalid information');
        }
    }

Es mala practica guardar la contraseña en texto plano por eso, se usan librerias como bcrypt para encriptarlas.
.
El segundo paramentro de bcrypt.hash indica cuantas veces ejecutara el algoritmo, en este caso ejecuta 5 veces el algoritmo, mientras mas veces se ejecute mas segura sera la contraseña, pero el proceso de generacion de la misma sera mas lento.
.
(lo recomendado son de 5 a 10 ejecuciones)

 async function login(username, password) {
        
        const data = await store.query(TABLA, {username: username});
        const passwordIsOk = await bcrypt.compare(password, data.password);

        if (passwordIsOk === true) {
            return auth.sign(data);
        } else {
            throw new Error('Informacion invalida');
        }

        
    }```

wow clase magistral!!

Recuerden actualizar node para que bcrypt pueda trabajar

me gustaría mucho que explicara cómo es que toma la decisión de hacer las funciones asincronas y cuando no es necesario.

Nunca había visto la capa de seguridad como la dice carlos! y me gusta la idea! Gracias !!

Así me quedó la función login. Muy cortita y fácil de leer

const login = async (username, password) => {
  const data = await store.queryUser( TABLE, { username } );

  // cifrate data.password; then compare both passwords after login
  return bcrypt.compare(password, data.password)
      .then( equals => {
         if( equals ) return auth.sign(data)
         else return 'Invalid password';
      });
}

Excelente se ve tan simple la logica, muy bien !!! 🤘🤘

Estupenda clase instructor Carlos, ahora me ha quedado más claro cómo podemos encriptar las contraseñas y compararlas con método compare que viene en este paquete para poder generar el Token.

Tuve problemas para usar bcrypt. Directamente utilicé bcryptjs

Es increible lo sencillo que se puede manejar en NodeJS, algo tan complejo como la seguridad.
.
Ni hablar de la explicación del profesor, un fenómeno!

No es mala practica guardar datos sensibles como el Password en el token?. Se que esta cifrado, pero no debería hacerse no? 🤔

En vez de usar promesa utilize algo sincrono de bcryp 😃

 

async function login(username, password) {
        const data = await store.query(TABLA, { username });

        if (bcrypt.compareSync(password, data.password)) {
            delete data.password;
            return auth.sign(data);
        } else {
            throw new Error("Informacion Invalida")
        }
    }```

aquí puedes decodificar y ver que hay en el payload de tu token

no puedo instalar bcrypt :’(