bcrypt node.js (auto-gen a salt and hash) - node.js

I am using the following code to hash (and hopefully salt) user passwords before I store them in my DB.
// hash the password before the user is saved
ConsultantSchema.pre('save', function(next) {
var user = this;
// hash the password only if the password has been changed or user is new
if (!user.isModified('password')) return next();
// generate the hash
bcrypt.hash(user.password, null, null, function(err, hash) {
if (err) {
logger.error("bcrypt.hash "+err);
return next(err);
}
// change the password to the hashed version
user.password = hash;
next();
});
});
What I am confused about, is the part
bcrypt.hash(user.password, null, null, function(err, hash) {
I got this code from a tutorial and I have seen it quite often searching for an answer.
Based on the documentation (https://www.npmjs.com/package/bcrypt) for bcrypt I would have expected the following code
const saltrounds = 10;
bcrypt.hash(user.password, saltRounds, function(err, hash) {
To be working but this breaks my program without an error.
My questions are:
Why are there two "null" arguments? What are they for?
Is the hash salted based on the code with the two nulls?
Thank you in advance for you help!

There is a difference between bcrypt and bcrypt-nodejs. The following code is from their docs at npmjs.com.
bcrypt hashing
bcrypt.hash(myPlaintextPassword, salt, function(err, hash)
or
bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash)
bcrypt-nodejs hashing
bcrypt.hash(myPlaintextPassword, null, null, function(err, hash)
Explanation
You are looking at the docs for bcrypt, not bcrypt-nodejs. If you are using node.js, you'll most likely want to use bcrypt-nodejs. I have multiple projects utilizing its features. The two null fields are for the salt and progress:
salt - [REQUIRED] - the salt to be used to hash the password.
progress - a callback to be called during the hash calculation to signify progress

I have used crypto library for hashing and it works great. Here is my code snippet
var salt = crypto.randomBytes(128).toString('base64');
var iterations = 10;
var keylen = 20;
crypto.pbkdf2(args.password, salt, iterations, keylen, function(succes, bcryptedPassword) {
console.log(bcryptedPassword.toString());
//Do actions here
});
Please check if it helps you or not

The following syntax is from the (abandoned?) bcrypt-nodejs module 1
bcrypt.hash(user.password, null, null, function(err, hash) {
You refer to the docs of the bcrypt module 2.
Make sure you're using the right module.

Related

Node Postgresql User Password Security

I've created a registration web page and I'm wondering what's the best way to upload password to server and how to store user passwords.
Currently, I just have a field for password and when the user clicks "submit", it makes a call to the server then insert the password into the db as is.
My question is at which step should I encrypt the password and what are some good methods of keeping this data secure?
I've looked around but haven't found much resource on this, maybe I'm not searching the right things.
The popular way of doing this in node is using bcrypt password encoder.
const bcrypt = require('bcrypt');
const saltRounds = 10;
const myPlaintextPassword = 's0/\/\P4$$w0rD';
const someOtherPlaintextPassword = 'not_bacon';
// hashing
bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
// Store hash in your password DB.
});
// comparing
bcrypt.compare(myPlaintextPassword, hash, function(err, result) {
// result == true
});

bcrypt is not checking case sensitivity of the password

I am using ExpressJS and MongoDB. I am using bcrypt for hashing the password before storing it in the database.
Here is the code :
if (bcrypt.compare(req.body.password === result.password))
How can I make it case sensitive? Thank you.
Your problem here is that you are using the bcrypt.compare function incorrectly.
From the docs found here: https://www.npmjs.com/package/bcrypt
bcrypt.compare(myPlaintextPassword, hash, function(err, result) {
// result == true
});
bcrypt.compare(someOtherPlaintextPassword, hash, function(err, result) {
// result == false
});
And here's a complete, working example with an upper vs. lower case password checked:
const bcrypt = require('bcrypt');
const testPassword = '12345678abcdefg';
// generate a hash:
bcrypt.hash(testPassword, 10, function(err, hash) {
// test a wrong password:
const nonMatchingPassword = '12345678ABCDEFG';
bcrypt.compare(nonMatchingPassword, hash, function(err, matches) {
console.log('should not match:', matches);
// test the right password:
bcrypt.compare(testPassword, hash, function(err, matches) {
console.log('should match:', matches);
});
});
});
The output from this example:
should not match: false
should match: true

Updating password in Mongoose with pre hook results in passport.js password check failing

Ive implemented a password authentication with passport and local authentication in Node.js that is as follows:
userSchema.pre('save', function (next) {
if (this.password) {
this.salt =
Buffer.from(crypto.randomBytes(16).toString('base64'), 'base64');
this.password = this.hashPassword(this.password);
}
next();
});
userSchema.methods.hashPassword = function (password) {
return crypto.pbkdf2Sync(password, this.salt, 10000,
64, 'sha512').toString('base64');
};
Now I added a pre hook for updating the password where I create a new salt and hash the new password. The update itself is executed, but the resulting new salt and password hash fail the password check.
I added this code (which is a bit raw, but for now I would be happy if the concept works):
userSchema.pre('findOneAndUpdate', function (next) {
if (this._update.password) {
this.salt =
Buffer.from(crypto.randomBytes(16).toString('base64'), 'base64');
this._update.salt = this.salt;
this._update.password = crypto.pbkdf2Sync(this._update.password, this.salt, 10000,64,'sha512').toString('base64');
}
next();
});
The update is done with this code:
users.findOneAndUpdate({email: req.body.emailadres },
{password: req.body.password}).exec();
I see the salt and password values being updated in the collection, but the authentication returns a failure on login after the update.
I'd expect that the update of the fields as in the above code should work. Am i missing something? Also, how is the hashPassword reusable for the update hook?

How should I store salts and passwords in MongoDB

I am trying to store passwords and salts in MongoDB and I'm not sure which datatype should be used. When I use strings, the encrypted password appears to be stored correctly, but the generated salt, which is created with new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');, seems to have characters that weren't recognized. For example, I have a salt stored as �y_�6j(�l~Z}0ۡ\" and I don't think this is correct.
Is the problem that it's stored as a string?
While registering a user, you can generate a hashed password using bcrypt. Let's call this password as P#1. Save this hashed password (P#1) in your database only, and not the salt.
While logging in a user, generate hashed version of the password which the user sends, let's call it P#2. Now you just have to match P# and P#2. If they match, the user is authenticated. This way you can perform authentication without actually saving the salt in your database.
I will try to put it in simple way with the help of an example.
// My user schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt-nodejs');
var userSchema = new Schema({
username: String,
password: String
});
// hash the password
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// checking if password is valid
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.password);
};
var User = mongoose.model('user', userSchema);
module.exports = User;
// My APIs for registering and authenticating a user
var User = require('/path/to/user/model');
app.post('/register', function(req, res) {
var new_user = new User({
username: req.body.username
});
new_user.password = new_user.generateHash(req.body.password);
new_user.save();
});
app.post('/login', function(req, res) {
User.findOne({username: req.body.username}, function(err, user) {
if (!user.validPassword(req.body.password)) {
//password did not match
} else {
// password matched. proceed forward
}
});
});
Hope it helps you!
Ankit Gomkale's answer is correct (and IMHO clean!), but you might wonder how it's possible to verify the hashed password is the same as the input string being tested.
This is because the output of bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); is not a "hashed password", it is a "hash string", of the form (source):
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
\__/\/ \____________________/\_____________________________/
Alg Cost Salt Hash
Therefore, this string contains the password hash, but also the salt. Verification of a password (e.g. in bcrypt.compareSync(password, this.password);) will use this salt, not create a new random salt.

Node js - Bcrypt - compare method returns false for the correct input password

I've been through various similar questions here and i tried them all, but still, the result is always "wrong password".
I'm using bcrypt for nodejs and my password hashes are stored in an Postgresql database.
The hash and compare methods are as follow :
generateHash : function(password, callBack){
bcrypt.genSalt(8, function(err, salt) {
bcrypt.hash(password, salt, callBack);
});
}
validPassword : function(password, callBack){
bcrypt.compare(password, this.password, callBack);
}
I'm using these function in the following piece of code :
//Generating hashing and DB storing
User.generateHash(password, function(err, hash) {
// if there is no user with that email
// create the user
var newUser = User.build({
email: email,
password: hash
})
.save()
.then(function(newUser) {
return done(null, newUser);
})
.catch(function(err){
return done(err, false);
});
});
//...
//Checking the password input for login
user.validPassword(password, function(err, res) {
if(err) throw err;
if(!res){
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
}
else{
// all is well, return successful user
return done(null, user);
}
});
I hope that was clear. Thanks in advance. Ciao.
Update I : callBack added to validPassword, although this didn't fix the problem. And i have also checked the this.password value, it's correct and as expected. So, the problem is still present.
I think you forgot to add callBack as parameter to
validPassword : function(password){
Try if adding that solves your problem, so change it to
validPassword : function(password, callBack){
Also, I don't know where your validPassword function is in, but you might want to check if this.password does indeed refer to the users password.
i just solved the problem. lol it was a series of errors that made this hard to figure it out. So i'm just going to enumerate what must be done to avoid such things :
The hash must be stored in the database as a varchar and not as a char. The latest cause the hash to be of a non correct length, and so the comparison will fail. varchar is the solution to this.
Handling the comparison result must be done inside of the callBack function. This is due to nodejs being asynchronous. This was correct (see code in the question) i just want to point it out. Otherwise, the result of the comparison would be undefined.
I hope this will help some of you.

Resources