Guys I have some general questions about interacting with my PostgreSQL DB my ExpressJS API and my React Native Frontend.
I managed to write some queries that for example check if the username that is entered in my RN app matches the one that is on the DB and returns its userID.
I know that on my DB every User has its Password that is being stored inside the DB in a hashed way.
How would a Query look like that would return for example the userID as I am doing it but only if the username exists and it matches the Password that is stored on the DB?
Do I need to know how the passwords are hashed on the DB?
The Query for userid:
static getUserId (username, callback) {
db.query(`SELECT userid FROM employee WHERE username = '${username}'`, (err, res)=> {
if(err.error){
return callback(err.error)
} else {
return callback(res)
}
})
}
The passwords are saved in the same employee table under password.
EDIT: I think I can take two WHERE statements like this:
`SELECT userid FROM employee WHERE username = '${username}' AND WHERE password = '${password}'`
but if a User enters his password inside the app it is not hashed so do I need to send the same hash method to compare these values?
Thanks in advance!
Best regards Faded.
You can use bcrypt.js for hashing your passwords.
To hash password in SignUp.js:
app.post('/signup',(req,res,next)=> {
//Password from request body of register request
const myPlaintextPassword = req.body.password
//saltRounds are typically set to 12
bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
// Store hash in your password DB with INSERT.
});
}
Now to compare with Hash in Login.js:
app.post('/login',async (req,res,next)=>{
const existingUser = await db.query(`SELECT userid FROM employee WHERE username = '${username}'`, (err, res)=> {
if(err.error){
return callback(err.error)
} else {
return callback(res)
}
})
const valid = await bcrypt.compare(req.body.password, existingUser.password);
if (!valid) {
res.status(401).send('Wrong pass');
return req.next()
}
}
You need to hash the incoming password and compare the two hashes.
That being said: if this is going to be at all used by real people I would suggest using a library to handle your auth instead of writing your own. There are a lot of things that can go wrong to make your application insecure.
Related
I've been experimenting with nosql databases recently, mostly mongodb and I came to a weird blockage. To keep it really short I started implementing user auth / profile creation. User and profile have a 1-1 relationship. When a user is created, so is the profile but with no values at the start except for the user id
user = new User({
username,
email,
password
})
user.password = await bcrypt.hash(password, salt)
const newUser = await user.save()
const newProfile = await new Profile({user: newUser.id})
await newProfile.save()
So this works just fine, I even added some checks to compare the newUser.id and newProfile.user, it's a match, they're identical
Now the problem arises when I try to update the profile in this code here, for some reason I think mongodb doesn't think the id values are the same, I've been going around this for a while and can't figure out what I'm doing wrong. So this piece of code returns NULL to my profile update endpoint and I have no idea why ( I'm using mongoose )
try {
const profile = await Profile.findOneAndUpdate(
{user: req.user.id},
{$set: profileData},
{new: true})
return res.json(profile)
} catch (err) {
console.log(err.message)
res.status(500).send("Server error")
}
I was thinking if this doesn't work out, I could just generate an id before making a doc and passing it to the collections as a custom field
There are no errors
I have a sign-in form. And I have stored our user information in MongoDB Atlas https://www.mongodb.com/cloud/atlas/.
My data is like
_id:60a64bee48f6eed16a566cf5
user_name:"test1"
user_password:"123456"
_id:60a64bee48f6eed16a566cf5
user_name:"test2"
user_password:"abcdef"
_id:60a64bee48f6eed16a566cf5
user_name:"test3"
user_password:"123456"
And I should retrieve the data that both user_name and user_password match.
My code is
app.post('/login', (req, res) => {
let userName = req.body.user_name;
let userPassword = req.body.user_password;
userCollection.find({user_name: userName}).toArray()
.then(results => {
console.log('success');
res.redirect('/')
// console.log(results)
})
.catch(err => {
console.error(error)
})
})
And my question is any other option to find the document that match the data like given user_name and user_password should match
Thanks for your suggestion.
Try this code its seems easy to understand verify both password and username
userCollection.find({user_name: userName},function(err,foundUser){
if(!err){
if(foundUser.userPassword == userPassword){
console.log('success');
res.redirect('/');
}
}
else{
console.log(err);
}
});
-
Use the below query
userCollection.find( { $and: [ {user_name: userName, user_password: userPassword } ] } )
we should never store the password directly in your DB, you should first encrypt the password by using any encryption library then store it in DB
Use
userCollection.find({user_name: userName, user_password: userPassword })
You can use findOne instead of find
https://docs.mongodb.com/drivers/node/usage-examples/findOne/
userCollection.findOne({user_name: userName, user_password: userPassword })
Note:- Don't store raw passwords, store hashed password
You can use https://www.npmjs.com/package/bcrypt to hash passwords.
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
});
async function update(id, userParam) {
const user = await User.findById(id);
// validate
if (!user) throw 'User not found';
if (user.username !== userParam.username && await User.findOne({ username: userParam.username })) {
throw 'Username "' + userParam.username + '" is already taken';
}
// hash password if it was entered
if (userParam.password) {
userParam.hash = bcrypt.hashSync(userParam.password, 10);
}
// copy userParam properties to user
Object.assign(user, userParam);
await user.save();
}
When I send an update request it updates everything in the body. I only need to send userid, username and user role and update to update only those fields. I am very beginner.PLEASE help me to solve my issue
You can find the document and update the field what you want by using "updateOne". for example, here I am going to update User collection's username only. mongodb's "updateOne" will fulfill that task here basically updateOne has 3 parameters.
search the document you can use any filed here I have used the _id field.
{ "_id": "232323"}
second parameater is {$set:{"username":"kalo"} this will set the new value.here you can use any number of fields.
User.updateOne({ "_id": "232323"},{$set:{"username":"kalo"}})
For More mongodb doc
If you are using Mongoose nodejs mongodb ORM read this. This doc says the same thing that I explained.
In your case you can simply use like below instead of await user.save();
await User.findOneAndUpdate({ _id: userid }, { username : username , userid: userid,userrole:userrole})
use the User not user
user.username = user.userParam;
This is the key Line I needed.It solved my issue....Although it's simple answer,it may be useful to some of the beginners like me.
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.