Safe password transfer between client and server [duplicate] - node.js

This question already has answers here:
Is it worth hashing passwords on the client side
(13 answers)
Closed 2 years ago.
I'm reading a lot about security lately and something really bothers me.
I'm using Node.JS and I wanna store user data in the database. I currently hash the password on the server and then I save it to DB. But when the user sends data to the server he sends just plain text. I think that is the wrong approach. I'm using Bcrypt btw.
The method that I wanna use is: when a user need's to sign in I hash the password on the client, and then I send a hashed password with a salt to the server. The server then hashes the password again and stores the result in DB alongside with the first salt, that the user has passed. That means I have serverHash(userHash(userPassword)) and userSalt.
When the user then does log in, I wanna fetch him a userSalt from DB and hash his userPassword using that salt. Then I send userHash(userPassword) to the server and then compare userHash(userPassword) and serverHash(userHash(userPassword)).
Is this method good and secure, or is there a better way to do this, can I maybe use some third-party library or I can get away with this approach?
EDIT:
If someone bumps into this, don't do this, TLS will probably do the job, if not there are certificates that will help I think, I'm not 100% sure, but don't take my word for it but.

Purpose of Database Hashing Password
hashing password in server solve worries about accidental access to database.
where we consider server script are executing in a safe environment.
Authorized User can leak any data without protection
when a user login using username/password we will give him/her Authorization to Actions and view some Data .
if any crackers intrudes:
our server script
client browser or
intermediate media (network interception)
our goal (protect authorization) will be ruined.
so hashing the password on client-side dosen't solve any issue, if a
cracker can access to client-side area or intercept the traffic
data.
for example : an authorized admin, with heavy password protection mechanism,
can leak html data which tends to be admin-only viewable, if a cracker just intercepts network traffic.
Solution : Traffic Encryption
instead of sending hashed-password to server-side, The connection should get Encrypted like with SSL.
Todays Web Development
in Web Development its a good practice to to use HTTPS (Http+Ssl) when dealing with sensitive Data and Actions (scenarios which includes logins)
even in modern browsers, they show a Warning when dealing with html <input type='password'/> and not using Https.

Related

How to NOT send a plain-text password to BE and still verify it

I am having a dillema now ..
I am building an application on VueJS and NodeJS .. and during the authentication, I need to verify whether the password and username match (obviously).
The problem is, I don't want to send the plaintext password from FE (VueJS) to the BE (NodeJS) but already encrypted with bcrypt
The problem is, there is no way for me to check if the given hash matches the stored one in the database. so this leaves me with sending the plain text password - but from my paranoid security perspective, it's not ok ...
How do you guys solve this?
It is standard practice to send "plaintext" passwords over HTTPS. The passwords are ultimately not plaintext, since the client-server communication is encrypted as per TLS.
Encrypting the password before sending it in HTTPS doesn't accomplish much: if the attacker got their hands on the encrypted password they could simply use it as if it were the actual password, the server wouldn't know the difference. The only advantage it would provide is protecting users that use the same password for multiple sites, but it wouldn't make your site any safer.
As indicated, generally the security layer of HTTPS is trusted.
Technically speaking, it is possible to split the password hashing in two. You can simply perform one number of iterations on the client (browser) and the remaining on the server. You want to perform at least one iteration on the server as you would otherwise get the value that the clients send to be stored in the database: i.e. getting a copy of the values in the database would directly leak all login credentials... not good.
So this would likely mean two separate bcrypt hashes to be performed if you want to keep using that algorithm. You can reuse the same salt I suppose, but storing a separate one should always be preferred. Of course, performing bcrypt at the client side will spike the CPU locally, which may hamper performance, spin up fans etc., and that's assuming the JS will run OK.
Finally, if the TLS is completely broken then somebody can simply inject a script that will leak the password. So hashing it locally will only increase security by a relatively small margin. It could still be somewhat useful against future decryption attempts, but in the end you'll have to rely on TLS anyways. So the answer to "How do you guys solve this?" is generally: we don't. It might make slightly more sense in a mobile app or full size application.
Interesting to know, there have been submissions such as Catena and Makwa to the password hashing competition that explicitly allow the client to perform part of the hashing. Generally this is more performed for offloading the password hashing to other systems and alleviate the use of valuable server resources.

Authentication with salted password

I'm using scrypt to generate strong hashes of the password of the user. I want to log the user in, but don't want to send the password in plaintext over the wire, how do I check if the password is correct (without a roundtrip), since it is salted?
I'm having a client / server scenario. The client is an application on a desktop computer (not a website, nor http server).
How can I achieve this? I came only this far: I'm generating the the salt + hash on the client, form a mcf out of it and send it to my server. Save the mcf to the database. I haven't send the password, just the hash which is practically useless (since scrypt should be quite strong, and would require a few million years to reverse it).
How can I now log the user into my service, without sending the plaintext password to the server to compare it? I can't rehash it, since it would result in a different hash due to a different salt? I would need to send the salt to the client, hash the password, send the hash to the server, compare it, and send some authentication token back.
How can I achieve this? Is an authentication token actually secure? It can be simply used to impersonate anyone, I guess?
don't want to send the password in plaintext over the wire,
Good idea, but if the connection is not encrypted (something like SSL/TLS), then whatever you send is plaintext. If you hash a password client-side, and send it over the network, then THAT is the password. Some would say that there is no benefit here, but it does prevent the user from exposing their actual password, which they probably re-use on other sites. (read more here)
Ideally you would use something like SSL/TLS to encrypt the connection. I guess if that wasn't possible, using asymmetric encryption with certificates on the message itself that you are sending would be an ok way of re-inventing the wheel, but I am hesitant to recommend that without having a security person look over it. It's very easy to screw up, and the rule is never roll your own crypto scheme.
If you can't verify/invalidate/update the public key, then it is not a good scheme.
I would need to send the salt to the client, hash the password, send the hash to the server, compare it, and send some authentication token back
The salt isn't supposed to be super secret, but it's not great to just give it away like that, especially to unauthenticated users. The authentication token, hash, salt, etc can all be intercepted if the connection is not encrypted. Even if they couldn't, you didn't solve the problem of users creating accounts through this method (maybe you don't need to, but it is worth mentioning).
You have to use asymmetric encryption where only the server can decrypt the data.
There is no short answer to your question, because there are so many pitfalls that can happen if you do it wrong. But as Gray says, you do need TLS protection.
I have two sources that give you detailed explanations on the right way to do this if you want to do client side scrypt processing.
Method to Protect Passwords in Databases for Web Applications. If you do not want to understand all the rationale, just jump to section 4 to see the implementation (where PPF = your scrypt).
Client-Plus-Server Password Hashing as a Potential Way to Improve Security Against Brute Force Attacks without Overloading the Server.
They are slightly different solutions but based upon the same ideas, and either should be good enough for you.

CouchDB Authentication

I've read a lot of things about authentication in CouchDB, especially regarding the Cookie Authentication.
I'm still making some tests and all seems working well, for instance with this command :
curl -vX POST $HOST/_session -H 'application/x-www-form-urlencoded' -d 'name=foo&password=bar'
I get a Cookie that I can use.
But my point is, anytime I see think kind of sample on the Web, the username and password are always sent in plain text.
I'm really new to security but what's the interest of the Cookie Auth method if I first have to send my credentials in clear ?
Is there a way to send at least the password hashed ?
With something like that IDK :
curl -vX POST $HOST/_session -H 'application/x-www-form-urlencoded' -d 'name=foo&hashed_password=hashed_bar'
Cheers
Arnaud
If you send your password hashed than all the attacker needs to know is your hashed password so it wouldn't solve the problem of sending your password in cleartext - now you would have a problem of sending your hash in cleartext.
Also remember that even if that solved the problem you would still be sending your cookie in cleartext being vulnerable to session hijacking.
(There's also the HTTP digest access authentication but not without its own problems - but CouchDB didn't support it last time I checked anyway.)
What you should do is to always use HTTPS for any authenticated CouchDB access with any network involved, except maybe the 127.0.0.0 network.
(And yes, pretty much all of the examples on the web and in books show using basic or cookie authentication over HTTP which in my opinion is a disaster waiting to happen.)
Using Https is the right answer.
I'll add a clarification on the importance to compute a hash on the server side.
The hash is a one way function transforming the input into the key value stored in the server. If someone hacks the server and gets the hashed input (key value) he won't be able to deduce the input value from it to impersonate you.
If you compute the key value on the client side and no one way tranformation is performed on the server, it is equivalent to store passwords in clear text. Someone who managed to get a copy of the key value stored on the server can easily impersonate you by simply sending the key value.
Thus applying on the server side a cryptographically secure one way function (i.e.sha256) with a salt/random seed on the submitted password is required to secure the password database.
Obfuscating the sent password by hashing it, in addition to hashing it on the server side, won't help mutch if the sent hashed value is always the same. However spying data sent through an SSL connection is not trivial.
There is however a significant benefit to hashing password on the client side. A brute force attack on the server by trying to guess the password using a common password dictionary would become hopeless because the hashing on the client side randomized the password.
We may add some salt to the hash to protect against use of hashed password dictionary. When the user typed his user id, ask for the user specific salt value to the server. Then use the returned salt or hash seed value to generate the hashed password on the client side.
Brute force password guessing maybe hindered on the server side by increasing the time interval between retries. But this generally works for one specific connection. The attacker may reconnect after every two attempts. It is then required to keep track of ip addresses to recognize such type of attacks.
As of version 1.1, CouchDB, supports API access via HTTPS. Instead of using an HTTPS proxy, you can use HTTPS directly, protecting passwords transmitted over the wire. See the Feature Guide for 1.1.

Keeping passwords safe

Situation 1 - Connecting the server to the database:
Its always said that passwords should not be stored in plain text, however to connect to the mysql database requires the password, in plain text it seems... I'm guessing the best solution to this is to store it in an encrypted form, decrypt it in my app as needed and then erase it from memory (SecureZeroMemory in windows I guess so the compiler cant optimise it out).
Situation 2 - Users logging into the server from a remote computer:
As for users passwords my plan is to never actually store the original password at all.
Instead I will store a randomly generated "salt", for each user, prefix there password with it then hash it, which seems to be a relatively common way. However I don't have an SSL connection available at this point, so I'm guessing the plain text passwords could be intercepted, what's a good solution to this?
What are good algorithms (links to C/C++ implementations would be handy as well if you have them) for doing this, a look on the net comes up with 100's of them?
EDIT:
If I got SSL, would the following be secure (assuming a strong hash algorithm is used), or should a different method be used?
Client requests salt for a user name
Client prefixes password with salt, then hashes it before sending the hash to the server
Server compares hash recieved to the one on the server for that user name
Connecting the server to the database
Just storing the database password in the server - encrypted or not - is a bad idea. It is obvious storing it in plain text, of course. And if you just store it encrypted, the server still needs the key to decode it. It is usually not very hard to find the key in the server code. The best solution is to let the user starting the server enter the password and store it nowhere. Alternatively - and probably even better - you can store all sensitive information - for example database users, passwords, and so on - encrypted and let the user starting the server enter a master key to decrypt this information.
Connecting a user to the server
This is really a hard problem and easy to mess up. A quote from this great article article on the topic I absolutely recommend reading.
No, really. Use someone else’s password system. Don’t build your own.
A good solution might be using the Secure Remote Password Protocol.
You are correct that if you're not using SSL then the passwords can be intercepted.
It is common practice to never decrypt a user's password, so keep it stored hashed with a salt and when the user types in their password you will add the salt and hash it, comparing it with the stored, hashed password. This will allow you to never have the decrypted version of the password every.
You really should look into securing the connection so that the password is secure when the user types it in.
Update to answer edited question:
If you have the communication secured using SSL you can still use any number of extra measures of security you like including hashing the password. As added security it is a good idea to remember that the password you store should be stored hashed with a salt. That salt should be kept safe and never be accessible anywhere except by your application. This way when the user submits the password you just add the salt and hash and you compare that version with the stored version.
Situation 1 - Connecting the server to the database
There isn't an easy answer here. In order to connect, the server needs the password (or symmetric key, or private key or whatever). It must get it either from the disk or some external means (like an administrator typing it at startup). Adding some indirection, such as encrypting all the sensitive stuff under a master password, can add some convenience but otherwise doesn't change the situation.
Typically, it is fine to put the password or key in a file on a server. If you do this, make sure to set the permissions on the file so that only the users that need it have access to it. This is an excellent reason to have different processes on your system run as different users, and to set up separate roles/accounts and passwords for each.
Situation 2 - Users logging into the server from a remote computer
You are headed in the right direction here, I think. What it sounds like you're asking for is a secure authentication protocol. You want one that provides mutual authentication and prevents a man-in-the-middle attack by failing if such an attack is attempted. There are many to choose from of course.
It is also worth mulling whether your authentication should operate based on "something you know" (passwords) or "something you have" (public/private keys). Assuming based on your question that what we're looking for is passwords, two that I like are SRP and Kerberos.
SRP was mentioned earlier, and that doesn't get nearly the attention it deserves. SRP has the advantage that it doesn't require the server to know the password, or key, or anything that an attacker could use to gain access. If you broke into a correctly configured server using SRP and stole all the data, you'd still need to do something like a dictionary attack on each key individually before you had anything you could use to impersonate a user.
I also like Kerberos because it is supported by tons of software (I know Postgres supports it, I've only found mentions of mysql not supporting any good authentication technology) and has a system of 'tickets' that provides a single sign on capability. Kerberos needs some other technology to help strengthen its initial authentication exchange and SRP would be great for that but I'm not sure they've done that yet. Something about it making the KDC (key server) stateful I think.
Kerberos' weakness is that you have to be more wary of the server storing the keys. While it doesn't store the passwords in plaintext, it does store the keys, which are essentially hashed versions of the passwords. And while the client doesn't exactly send either the password or the key straight over when authenticating (this is a Real auth protocol after all), it does use the hashed password as the key, and so anyone else who knows the algorithm and knows the key could do the same. We say that the server stores a "password equivalent". As a result, all the manuals tell administrators to put the kerberos services on their own separate, locked-down boxes to minimize the chance of compromising their contents.
The nice thing is, once you settle on a strong authentication exchange, other good things typically fall out of it for free. You end up with both parties sharing a mutual 'secret' that can be used once for the duration of the session, never sent over the wire, and can't be known by a third party. Want encryption? There's the key, all ready to go. This is exactly how SRP-secured SSL is defined in RFC 5054.
Not sure if this is what you are asking for.
But a simple PHP example using the built in sha1 function:
// Check the hashed password from the database
if (sha1($salt.$password) == $providedPassword)
{
// User is authenticated
return TRUE;
}
else
{
// User is not authenticated
return FALSE;
}
One thing you could do is also hash the password with javascript before it is sent over the wire. The question is how is the salt string shared between client and server? One possibility is to use a session variable. And then use the session variable to unhash the password afterwards on the server. This would mean that the man in the middle would need to know one other piece of info to make sense of the password. Not as secure as SSL, but perhaps an extra layer of defense against casual network sniffers.
I could also imagine a hashing scheme linked to some sort of captcha system used to salt the password on the local client before sending over the wire. The client would be providing the text for the salt string by completing the captcha. You could look it up on your end.
The main concern is the man in the middle not understanding the plain text password.
SSL should be used, but the above techniques might be useful where SSL is not possible.
Newer MySQL uses hashed password over the wire, so you don't have to worry about man-in-the-middle.
If you worry about the password stored in your configuration file, you can encrypt the configuration file with a password. However, the problem is that you have to enter a password to start your application.
I wrote a similar application over 15 years ago. Back then, PGP was my choice. I am not even sure it's still around.

Website login: how should user credentials be sent to the server for verification?

I'm working on a project in which remote clients need to log in to a webserver. I'm not looking for examples in any particular language; just a general idea of the security concerns involved.
The basic question is:
How should user credentials be passed to a webserver for verification?
I'm picturing your typical website login. One field for username, and another for password. You type in both and click "Log In". What happens next?
I can imagine a few scenarios:
Credentials are sent to the server as plain text. A server-side script creates a hash of the password and compares it to the stored hash for the user.
Credentials are encrypted locally, and the result is sent to the server. The server decrypts the credentials and continues as in #1
Something I haven't thought of yet? I'm new to this. Go easy on me!
Option #1 strikes me as weak because the credentials are sent over the internet in plain text.
I see option #2 as not much better than option #1. If someone intercepts the encrypted credentials, can they not just send those to the server another time, and still manage to log in?
Any insight is appreciated.
edit: the "Related" sidebar suggests this question, which mentions a client/server handshake with a salt added to the password. Is that the right way to go?
Option 1 is by far the default. The plaintext weakness is usually overcome by enforcing SSL during the login so that the password is at least encrypted during transit.
Edit: I suggest you follow the accepted answer for that question.
Don't forget to require a nonce for your request. This will help protect you against replay attacks.
Edit the second: Wayne thoughtfully mentioned that you should salt your password before you hash. Here are some basic tips:
It doesn't matter if your salt is a prefix, postfix, or infix
Your salt should be large, random, and complex.
Your salt should be unique per salted value. The salt itself doesn't need to be encrypted.
Why not SSL the communications? Being able to observe the conversation gives me insight into your app. Encrypt the entire communication, not just the credentials.
Edit: Always use salt for a locally stored hash. Windows continues to fail as far as brute forcing locally hashed passwords because they do not salt by default.
The simplest answer is to get an SSL certificate for your server. There's really no reason to mess around with creating your own encryption techniques in this particular application. As you've noted, if the connection isn't encrypted, you leave yourself open to man-in-the-middle attacks, regardless of whether the client or the server is doing the password encryption. Encrypt the connection, and you don't have to worry about it.
On the client side you only have a browser that can render HTML and submit forms. Who's gonna encrypt stuff?
Send login and password in plain text (SSL it if you have concerns). On the server side you can do whatever you want with it (preferrably hash and salt password before storing them in the database).
You might also want to consider using multiple iterations of the hash algorithm, 1000 iterations will slow things down nicely and make rainbow tables that much harder to create

Resources