I use the nodejs bcrypt library for better password protection.
I am not sure i understand exactly how to use it, but i got this so far:
//A module containing this login function:
login: function(credentials,req,res) {
//"credentials" is containing email and password from login form
var query = 'SELECT password, email FROM users WHERE email = ? LIMIT 1';
client.query(query,[credentials.email], function(err, results) {
if (results[0]) {
//Compare passwords
if (bcrypt.compareSync(credentials.password, results[0].password)) {
//Set session data and redirect to restricted area
}
}
});
}
I removed all the error handling here in the example so that its easier to read the code.
1.This works and i am able to login and set the session. But is this all there is to it? Am i missing something?
2.Looks like the salt is prepended to the password when generating hash. Dont I have to save the salt in db?
Any help appreciated
Yes, this is all there is to it! The salt you generate when encrypting the password originally is used to prevent against rainbow table attacks; you do not need to persist it.
Related
I tried to dig in the sanitize function but i didn't find the answer that I wanted, the question is how to check if a user input doesn't contain any sql injection? i'm using Nest JS (similar to node) if you have any idea of how I can do that it would help me a lot!
Generally speaking: You can't. Any input which might be SQL injection could, conceivably, also be genuine input (at least in certain narrow circumstances).
Don't try to detect SQL injection. Instead, use placeholders where possible and proper escaping where not.
The issue is not on the NestJS side, it is on how you build the SQL query to execute.
You may use #nearform/sql that:
A simple SQL injection protection module that allows you to use ES6 template strings for escaped statements. Works with pg, mysql and mysql2 library.
It will protect you against malicious users input.
This module is battle-tested and already in production for Covid Government Tracker.
You can use prepared statements to avoid sql injection attacks
This blog post explains it quite well. for reference a snippet from the post.
function authenticate(req, res, next){
const username = req.query.username,
password = req.query.password
let preparedStatement = new sql.PreparedStatment(),
sqlQuery = "select * from users where (username = #username and password = #password)"
preparedStatement.input('username', sqlVarChar(50))
preparedStatement.input('password', sqlVarChar(50))
preparedStatement.prepare(sqlQuery)
.then(function(){
return preparedStatement.execute({username: username, password: password})
.then(function(recordset){
if(recordset.length == 1){
loggedIn = true
//successful log in
} else {
//authentication failed
}
})
})
.catch(next)
}
I using Adonis connect with a MSSQL DB who doesn't own a crypted password, but a i need to generate a token to reuse (because that i using Auth) but it does not work.
reading the documentation, i try to "Hash" that password and them auth, did not work. So i try, encrypt and them auth, nope again.
And finally i try to crypt, hash and them Auth... And them not work :|
Someone how get pass for this, can help me?
I don't know if it's possible without encrypted password. Keeping passwords unencrypted is not a good idea.
You can encrypt all password with this code :
const Hash = use("Hash");
const users = await User.all();
users.rows.forEach(async u => {
u.password = await Hash.make(u.password);
await u.save();
});
!! Only run one time
Hello I need some help with this issue after I search the solution and I have not found yet,
I want to compare 2 hash password with bcrypt of the same password,
how do I do it?
for example:
I have these 2 hash password that came from the same password in bcrypt:
var password = E#Js#07Do=U$
var hash1 = $2a$10$fKAyjaG0pCkisZfRpKsBxursD6QigXQpm1TaPBDZ4KhIZRguYPKHe
var hash2 = $2a$10$mgApOcRIp7RSK3lRIIlQ5e/GjVFbxAFytGAEc0Bo17..r8v2pPR22
// that's not working for me
bcrypt.compare(passwordHash, userPasswordLoginHash, function(err, isMatch) {
if (err) throw err;
if(isMatch){
console.log('correct password!')
}
callback(null, isMatch);
});
how can i compare them, to determine that they came from the same password, by using bcryptjs npm package?
This is impossible by design - as a core security property of true password hashing.
If you could compare two password hashes without knowing the original password, then if an attacker cracked one password on the system, they would instantly know the passwords of all users who are using that password, without any additional work. It should be immediately obvious why this would be a bad thing.
For example, if passwords were stored using a hash inappropriate for password storage (such as MD5), then if 50 users had a password of 'password', then all of their hashed passwords would have the identical MD5 hash ('5f4dcc3b5aa765d61d8327deb882cf99'), and cracking one of them would reveal the password of all 50 users.
You can't do that with a modern password hash like bcrypt. The only way to "compare" two modern password hashes is to know the plaintext in advance, and then apply the algorithm using the salt in each hash. And even if two users have the same password, the attacker has to perform the same expensive computation to crack each of them independently, because the unique salts make each hash unique.
More generally - and this may sound a bit bold - but there is no legitimate use case for any system or administrator to ever compare two different users' passwords. User passwords should be 100% independent and 100% opaque to the system once stored. If a system or business case requires this kind of comparison, it should be redesigned to eliminate that requirement.
"With bcrypt lib you compare plain text password to the one hashed using the same lib."
The problem is with a micro services architecture, that is very insecure. If I have a front end passing an unhashed password to the backend, the unhashed password is getting logged (possibly in multiple places) before it gets compared against the hash in the DB on the system backend.
With bcrypt lib you compare plain text password to the one hashed using the same lib.
Say you hashed a password
const myPlaintextPassword = 'E#Js#07Do=U$'
bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
// Store hash in your password DB.
// example output, taking your hash
// hash = $2a$10$fKAyjaG0pCkisZfRpKsBxursD6QigXQpm1TaPBDZ4KhIZRguYPKHe
});
You compare like:
// db query, get hashed password, found hash
// hash = $2a$10$fKAyjaG0pCkisZfRpKsBxursD6QigXQpm1TaPBDZ4KhIZRguYPKHe
// User input again:
const myPlaintextPassword = 'E#Js#07Do=U$'
bcrypt.compare(myPlaintextPassword, hash, function(err, res) {
// res is true as the original password is the same
// res == true
});
For a bit extra security you can encrypt the password in the front-end and decrypt and compare in the back-end
I want ask something about firebase security. How to handle following situations?
User is creating account with createUserWithEmailAndPassword() function, then i save his username,email,created_at...to realtime db. But what if data are not saved correctly. His account is created and he is logged in automatically but data is not stored.
I have some registration logic... for example unique usernames... so before creating acc i check if this username exist in realtime db. But he still can call createUserWithEmailandPassword() from js console and account is created.
For situation one:
According to the firebase docs (https://www.firebase.com/docs/web/api/firebase/createuser.html), creating a user does not automatically authenticate them. An additional call to authWithPassword() is required first. In order to ensure that a user isn't authenticated without valid data, you could run a check to the server to make sure the data is saved correctly before authenticating.
Edit: Nevermind that; looks like firebase does auto-auth now - take a look at what I wrote below.
Now a concern with this approach would be if your app allowed people to authenticate with an OAuth provider like gmail, then there is no function for creating the user before authenticating them. What you may need to do is pull the user data from the firebase, determine if it's valid, and if its not valid show a popup or redirect that lets the user fix any invalid data.
For situation two:
If you wanted to make sure that in the case of them calling createUserWithEmailAndPassword() from the console a new user is not created, you could try something like this with promises;
var createUserWithEmailAndPassword = function(username, password) {
var promise = isNewUserValid(username, password);
promise.then(function() {
// Code for creating new user goes here
});
}
In this way, you never expose the actual code that makes a new user because it exists within an anonymous function.
I don't think that this could solve the problem entirely though because firebases API would let anyone create an account using something
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.createUser({
email: "bobtony#firebase.com",
password: "correcthorsebatterystaple"
}
(Taken from https://www.firebase.com/docs/web/api/firebase/createuser.html)
If you wanted to make sure that server side you can't ever create a user with the same user name, you'd need to look into firebases's rules, specifically .validate
Using it, you could make sure that the username doesn't already exist in order to validate the operation of creating a username for an account.
Here's the firebase doc on rules: https://www.firebase.com/docs/security/quickstart.html
And this is another question on stack overflow that is quite similar to yours. Enforcing unique usernames with Firebase simplelogin Marein's answer is a good starting point for implementing the server side validation.
First save the user credentials in the realtime database before you create the user:
var rootRef = firebase.database().ref('child');
var newUser = {
[name]: username,
[email]: useremail,
[joined]: date
};
rootRef.update(newUser);
After adding the Usersinfo into the realtime database create a new user:
firebase.auth().createUserWithEmailAndPassword(useremail, userpassword).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
When an error occured while inserting the data in the realtime database, it will skip the createuser function.
This works fine for me, hope this helps!
So I'm developing a website using php, mysql and javascript, and also 'sha512' to encrypt passwords of members using the code :
$password = filter_input(INPUT_POST, 'p', FILTER_SANITIZE_STRING);
$random_salt = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
$password = hash('sha512', $password . $random_salt);
the p value is comming from :
function formhash(form) {
var password = randomString();
var p = document.createElement("input");
form.appendChild(p);
p.name = "p";
p.type = "hidden";
p.value = hex_sha512(password.value);
password.value = "";
form.submit();
}
function randomString() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 9; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
My idea here is to reset user password by entering their email and generate random 8 characters then send it directly to their email.
The problem I'm facing now is how to get the actual password (not encrypted) that has been generated so it can be automatically sent to the email of the member who requested to reset their password?
Good question.
First, you should never send users their passwords in plaintext. It's considered a bad security practice for a few reasons. If anyone gets access to the email, then they have the password and can hijack the user account. Second, hashing is a one-way form of encryption where you turn the password into gibberish. The big value in hashing is that the same password will always be turned into the same gibberish-- everytime. This means you can do password matching without ever storing the raw password. The reason you're supposed to hash a password and not do 2-way encryption like AES-256, is that 2-way encryption requires the creation, management, and securing of encryption keys which can be hard. Hashing is just easier and more secure for the vast majority of developers.
So how should you implement password reset if you can't send the raw password?
You send the user an email with a link to a secure reset page AND a one-time use reset token that expires within a certain window. This way, if someone get's access to the email then the window of risk is limited to the short window.
There are a variety of ways to build this yourself but an easy approach to getting a one-time use token you don't have to store or manage is to offload user management to a microservice like Stormpath where it takes care of all the user management for you-- password reset, password storage, user profiles, authentication, etc.
For password reset here's what it would look like:
User initiates password reset work on a web page
You make API call to stormpath with user's email address or username
Stormpath sends out reset email to user (your "from" address, custom HTML, etc) with a link + token. The reset token that is unique, one-time use, and expires if not used within 24 hours
User clicks on the link and lands on the reset page
You pull the token from the URL and check Stormpath for token verification
User submits new password
Stormpath sends out reset success message (your "from" address, custom HTML, etc)
You can build your own UIs in this flow so the user never knows Stormpath exists.
Now, you don't have to manage, store, or secure any passwords or reset tokens in your database.
Here's are some links to the community-managed PHP SDK.
http://docs.stormpath.com/php/quickstart/
http://docs.stormpath.com/php/product-guide/
Full Disclosure - I work at Stormpath
and also 'sha512' to encrypt passwords
You're not encrypting them, you're hashing them. A hash is a one-way function. You can't take the result of a hash function and get the original. There are many possible original chunks of data that can result in the same hash.
The whole point of hashing in this context is to be able to check passwords without ever actually storing the user's password. You shouldn't send the user their password in e-mail, as e-mail is sent over the internet unencrypted. If you must have the original pre-hashed data for some reason, you must store it before you hash it.