How to Hash Passwords Before Posting and Then Using Bcrypt

How should I hash passwords before posting and then using BCRYPT?

What is done on the client side is not really controlled by you. What I mean is that even if you hash your password it's possible for a client to get the password before hashing/encryption.

var password = document.getElementById('login').value;
console.log(password); // It is as simple as it
//hash password...

Above a simple example to explain, the client could get the password like this, or someone else could get it using a XSS attack. You should do your best to protect your clients from XSS, but then you can't control what happens on the client side.

If what you fear is a Man In The Middle (MITM) attack, the most important thing is to use a TLS certificate with a correct algorithm (it depends on the OpenSSL version of your server).

In short, using HTTPS is what you should do to protect your clients from a MITM attack.

So according to me, it's not required to hash/encrypt the passwork before sending it.

Is there any way to hash a password with bcrypt before sending it with POST method?

Unfortunately, even if you did what you propose, it would still not result in a secure connection, thus rendering it vulnerable to a Man in the Middle attack. As discussed in the below comments, any hashing you do client-side renders the password pointless as it will require you to send the hash over the wire, to compare to another hash server-side. The attacker (MitM) could just use the hash to authenticate in this case.

If you want secure communication, you must (at least) implement TLS/SSL.

Should I hash the password before sending it to the server side?

This is an old question, but I felt the need to provide my opinion on this important matter. There is so much misinformation here

The OP never mentioned sending the password in clear over HTTP - only HTTPS, yet many seem to be responding to the question of sending a password over HTTP for some reason. That said:

I believe passwords should never be retained (let alone transmitted) in plain text. That means not kept on disk, or even in memory.

People responding here seem to think HTTPS is a silver bullet, which it is not. It certainly helps greatly however, and should be used in any authenticated session.

There is really no need to know what an original password is. All that is required is a reliable way to generate (and reliably re-generate) an authentication "key" based on the original text chosen by the user. In an ideal world this text should immediately generate a "key" by salting then irreversibly hashing it using an intentionally slow hash-algorithm (like bcrypt, to prevent Brute-force). Said salt should be unique to the user credential being generated.
This "key" will be what your systems use as a password. This way if your systems ever get compromised in the future, these credentials will only ever be useful against your own organisation, and nowhere else where the user has been lazy and used the same password.

So we have a key. Now we need to clean up any trace of the password on the clients device.

Next we need to get that key to your systems. You should never transmit a key or password "in the clear". Not even over HTTPS. HTTPS is not impenetrable. In fact, many organisations can become a trusted MITM - not from an attack perspective, but to perform inspections on the traffic to implement their own security policies. This weakens HTTPS, and it is not the only way it happens (such as redirects to HTTP MITM attacks for example). Never assume it is secure.

To get around this, we encrypt the key with a once off nonce.

This nonce is unique for every submission of a key to your systems - even for the same credential during the same session if you need to send it multiple times. You can reverse said nonce (decrypt), once it arrives in your own systems to recover the authentication key, and authenticate the request.

At this point I would irreversibly hash it one last time before it is permanently stored in your own systems. That way you can share the credential's salt with partner organisations for the purposes of SSO and the like, whilst being able to prove your own organisation cannot impersonate the user. The best part of this approach is you are never sharing anything generated by the user without their authorisation.

Do more research, as there is more to it than even I have divulged, but if you want to provide true security to your users, I think this method is currently the most complete response here.

TL;DR:

Use HTTPS.
Securely hash passwords, irreversibly, with a unique salt per password. Do this on the client - do not transmit their actual password. Transmitting the users original password to your servers is never "OK" or "Fine". Clean up any trace of the original password.
Use a nonce regardless of HTTP/HTTPS. It is much more secure on many levels. (Answer to OP).

How to pass a hashed password in a promise before posting it to the database using a Node.js server?

You could simply move your database queries, to inside the callback of the hash, so that when the hash call back is ready it would then save it.

var bcrypt = require('bcrypt');

app.post('/api/users', function(req, res) {
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(req.body.password, salt, function(err, hash) {
var newUser = new User({
email: req.body.email,
name: req.body.name,
password: hash
});

newUser.save(function(err) {
if(!err) {
return res.send({ status: 'User created' });
} else {
if(err.name == 'ValidationError') {
res.statusCode = 400;
res.send({ error: 'Bad Request' });
} else {
res.statusCode = 500;
res.send({ error: 'Internal Server Error' });
}
}
});
});
});
});

Or use the synchronous call of bcrypt.hashSync but synchronous is not good practice when trying to work with Node.

But it could be like password: bcrypt.hashSync(req.body.password, salt)

If I understand correctly what you're asking, you want to save the user, after the password is hashed?

How do we hash a put request password?

Solution 1: Easy Way

For your personal solution, without really modifying the code, it works like the following.

// updating  a user
router.put('/:id', async (req, res) => {
const {error} = validate(req.body)
if (error) return res.status(400).send(error.details[0].message)

// Why not make the hash function here?
const salt = await bcrypt.genSalt(10)
const newPassword = await bcrypt.hash(req.body.password, salt)

const user = await User.findByIdAndUpdate(req.params.id, {
$set : {
name: req.body.name,
email: req.body.email,
password: newPassword
}
})

if (!user) return res.status(404).send('User with that id does not exist')


res.send(user)
})

You have a mistake in your user.password call. The findByIdAndUpdate method does not return an object that you can modify instantly. In above workaround, we simply move the function so that it hashes the new password first before updating your document.

Solution 2: My Own Style

For my personal solution, I'd go like this. Let's say that you have a userModel that stores the schema of your User entity. I will add a new middleware that will run every time the password changes.

/** your user schema code. **/

userSchema.pre('save', async function (next) {
// Only run the encryption if password is modified.
if (!this.isModified('password')) {
return next();
}

// Hash the password with BCRYPT Algorithm, with 12 characters of randomly generated salt.
this.password = await bcrypt.hash(this.password, 12);
next();
});

Next, we'll create a new dedicated route in order to handle password changes. I think it's better if we define a new route for it as passwords are sensitive data. Below is pseudocode, don't instantly copy and paste it, it wouldn't work.

const user = await User.findById(...);
user.password = req.body.password;
await user.save({ validateBeforeSave: true });

Remember that save middleware runs every time after the save command is run.

Further reading about Mongoose's middlewares here.

Mongoose bcrypt set password and saving asynchronously

UserSchema.methods.setPassword = function (password) {
return new Promise((resolve, reject) => {
bcrypt.hash(password, saltRounds, (error, hash) => {
if (error) {
reject(error);
} else {
this.password = hash;
resolve(true);
}
})
})
}

and then call

await user.setPassword(req.body.user.password);

or maybe catch the error, idk

How do you use bcrypt for hashing passwords in PHP?

bcrypt is a hashing algorithm which is scalable with hardware (via a configurable number of rounds). Its slowness and multiple rounds ensures that an attacker must deploy massive funds and hardware to be able to crack your passwords. Add to that per-password salts (bcrypt REQUIRES salts) and you can be sure that an attack is virtually unfeasible without either ludicrous amount of funds or hardware.

bcrypt uses the Eksblowfish algorithm to hash passwords. While the encryption phase of Eksblowfish and Blowfish are exactly the same, the key schedule phase of Eksblowfish ensures that any subsequent state depends on both salt and key (user password), and no state can be precomputed without the knowledge of both. Because of this key difference, bcrypt is a one-way hashing algorithm. You cannot retrieve the plain text password without already knowing the salt, rounds and key (password). [Source]

How to use bcrypt:Using PHP >= 5.5-DEV

Password hashing functions have now been built directly into PHP >= 5.5. You may now use password_hash() to create a bcrypt hash of any password:

<?php
// Usage 1:
echo password_hash('rasmuslerdorf', PASSWORD_DEFAULT)."\n";
// $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// For example:
// $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

// Usage 2:
$options = [
'cost' => 11
];
echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n";
// $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C

To verify a user provided password against an existing hash, you may use the password_verify() as such:

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
Using PHP >= 5.3.7, < 5.5-DEV (also RedHat PHP >= 5.3.3)

There is a compatibility library on GitHub created based on the source code of the above functions originally written in C, which provides the same functionality. Once the compatibility library is installed, usage is the same as above (minus the shorthand array notation if you are still on the 5.3.x branch).

Using PHP < 5.3.7 (DEPRECATED)

You can use crypt() function to generate bcrypt hashes of input strings. This class can automatically generate salts and verify existing hashes against an input. If you are using a version of PHP higher or equal to 5.3.7, it is highly recommended you use the built-in function or the compat library. This alternative is provided only for historical purposes.

class Bcrypt{
private $rounds;

public function __construct($rounds = 12) {
if (CRYPT_BLOWFISH != 1) {
throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
}

$this->rounds = $rounds;
}

public function hash($input){
$hash = crypt($input, $this->getSalt());

if (strlen($hash) > 13)
return $hash;

return false;
}

public function verify($input, $existingHash){
$hash = crypt($input, $existingHash);

return $hash === $existingHash;
}

private function getSalt(){
$salt = sprintf('$2a$%02d$', $this->rounds);

$bytes = $this->getRandomBytes(16);

$salt .= $this->encodeBytes($bytes);

return $salt;
}

private $randomState;
private function getRandomBytes($count){
$bytes = '';

if (function_exists('openssl_random_pseudo_bytes') &&
(strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL is slow on Windows
$bytes = openssl_random_pseudo_bytes($count);
}

if ($bytes === '' && is_readable('/dev/urandom') &&
($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
$bytes = fread($hRand, $count);
fclose($hRand);
}

if (strlen($bytes) < $count) {
$bytes = '';

if ($this->randomState === null) {
$this->randomState = microtime();
if (function_exists('getmypid')) {
$this->randomState .= getmypid();
}
}

for ($i = 0; $i < $count; $i += 16) {
$this->randomState = md5(microtime() . $this->randomState);

if (PHP_VERSION >= '5') {
$bytes .= md5($this->randomState, true);
} else {
$bytes .= pack('H*', md5($this->randomState));
}
}

$bytes = substr($bytes, 0, $count);
}

return $bytes;
}

private function encodeBytes($input){
// The following is code from the PHP Password Hashing Framework
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

$output = '';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}

$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;

$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (true);

return $output;
}
}

You can use this code like this:

$bcrypt = new Bcrypt(15);

$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);

Alternatively, you may also use the Portable PHP Hashing Framework.

Using bcrypt for user passwords

Edit:
The problem is you have the order wrong, you need the password, then the stored hash.

$check = $hasher->CheckPassword($password, $stored_hash);

Source

This matters, as I said before (below) the stored hash is used to decide how to hash the password to compare, hence your wrong argument order will cause failure.

Answer from before:

You don't decrypt a hash, you check it by hashing the comparable data in the same way. BCrypt hashes include the hash, the salt and the number of rounds, so there should be no problem in checking this.

The reason that the hashes are never the same is the salt will be different each time. This is to protect from rainbow table attacks.

As far as I can tell, your check is sound. The problem must be elsewhere. Are you sure that $user->password actually contains the hash in full? BCrypt hashes are 60 characters, so make sure it isn't being truncated.



Related Topics



Leave a reply



Submit