User Authentication

Oct 18, 2022

Users

Storing Passwords

A site should not be storing your clear text credentials; a compromise of the database will give the attackers all usernames and passwords.

This is one of the reasons why you should not use the same username/password on multiple sites; a compromise of one site could lead to your account being compromised on other sites.

Password Hashing

Hash – a one way function that will create a “fingerprint” string of another string.

  • This hash cannot be reversed
  • A change in the input, even a small one, will drastically change the value of the hash
  • To see if the user has entered the correct password, we hash the input and compare that hash to the hash in the database

Hashing is not enough

Multiple users with the same password will have the same hash

Attackers who obtain the hashed passwords can attempt to crack the hash by using dictionary-based or brute force attacks where different passwords are hashed and compared to the hash from the database

Lookup tables are a very efficient way to crack hashed passwords, as they store the pre-computed hash to password values

Add a salt

Remember that a minor change to the input of the hash function will drastically change its output

By adding a random salt to a user’s password, we will drastically change the output and by using a random salt for each user, no two users will end up with the same hash even if they have the same password

The salt doesn’t have to be secret, so we can store it in the database

Generating a hash in Node with BCrypt

Install the bcrypt dependency with: npm install bcrypt And require it in your JavaScript file with: const bcrypt = require('bcrypt');

To hash a string, do this in an async function: const hashedString = await bcrypt.hash("string to hash" The 10 represents the amount of effort it takes to generate the the hash.

ˇThis can be increased as computers get faster to help prevent brute force password cracking.

COMPARING HASHES

For cases like passwords, we will oen want to hash the input password and compare it against a stored hash. bcrypt has a convenience method that can be used in an async function:

const authResult = await bcrypt.compare("some plain text" , storedHash);

This bcrypt.compare() will hash the string with the salt in storedHash, compare the new hash to the old hash, and return true if they match or false if they don’t.

Example User Creation

const username = req.body.username;
bcrypt.hash(req.body.password, 10, (err, hashedPassword) => {
if (err) {
  console.log('Hash Error: ' + err);
}
console.log(hashedPassword);
const sql = 'INSERT INTO users (username, password) VALUES ($1, $2)';
const params = [username, hashedPassword];
db.get(sql, params, (dberr, data) => { 
    if (dberr) {
        console.log('DB Insert Error: '+ dberr);
    }
    console.log(data); 
  });

Example User Authentication

const query = 'SELECT * FROM users WHERE username = $1';
const parameters = [req.body.username];
const result = await db.run(query, parameters);
if(result.rows[0]) {
  const auth =  bcrypt.compare(req.body.password, result.rows[0].password);
  if (auth) {
    req.session.user = result.rows[0];
    req.session.save(() => res.redirect('/secret-info'));
  }
}