What happens between the time a user sends a password and when the server receives it? - encryption

I'm trying to understand something. When I implement PBKDF2 in a server and client, it is my understanding (could be way wrong, sorry), that the server keeps the encrypted/hashed password in the database, and the user sends his or her password over the net and then it is checked by the server for validity.
What Im curious about is, exactly how do I prevent the users submission over the net to be seen and the users password exposed? do I Just depend on the networking library or SSL to protect this information?
How do i make sure the the password that's being sent over the net is in a way that cannot be exposed easily, but can still be read by the server to check against the hash?
Would it be wise to perform an SHA2 hash on the password client side, and then send that to the server and then check the sha2 has against the PBKDF2 hash? The server will never really even know the users password, the only possible recovery option is to reset it. Is this type of system acceptable?
What kinds of these things are done normally by the professionals?

When I implement PBKDF2 in a server and client, it is my understanding (could be way wrong, sorry), that the server keeps the encrypted/hashed password in the database, and the user sends his or her password over the net and then it is checked by the server for validity.
This is basically correct. When setting up an account the user sends user and pass to the server. The server stores user and PBKDF2(pass) and then discards pass. When logging in the server looks up against the user column and compares PBKDF2(pass_as_submitted) to the value stored when the account was set up. If they match, the user is authenticated.
Do I just depend on the networking library or SSL to protect this information?
In the sort of situation you're talking about, yes.
Would it be wise to perform an SHA2 hash on the password client side, and then send that to the server and then check the sha2 has against the PBKDF2 hash?
No. The problem here is you're just changing the thing you're keeping from the user's password to a hash of the user's password. It's still known to an attacker who can read the database.
(There are reasons this is marginally better than knowing the password, most particularly in case of password reuse. However, these do not justify such an approach.)
It's worth pointing out as well that SHA2(password) will not match PBKDF2(password).
What kinds of these things are done normally by the professionals?
First, use TLS (aka SSL). Having a good, encrypted connection between client and server is first priority. For a website, you should use TLS on every page, not just when sending the password. At the very least it must be used on the login page and on the request that receives username and password information.
Your TLS connection should be set up properly: it should use HSTS if appropriate (and it's a website). It should avoid outdated algorithms (only support TLS 1.1+ if possible). It should use appropriate cipher modes.
Beyond that, it depends on your use case. Perhaps it's worth implementing two factor authentication - be it using TOTP or SMS codes or similar. Perhaps you should be looking at logins without passwords, for example using client-side TLS certificates or OAuth2 tokens. Maybe you should use an existing authentication library like Kerberos. Maybe you need to look at password policies to ensure users are setting good passwords or pass phrases.
These questions are complex and depend on your use case. Thinking about them is the big first step most people don't take. Using PBKDF2 is a great start but there's no universal answer. If possible, get an expert to do your security analysis. If not, open source plus some promo can often get people to look at it. Worst case scenario, read up on security, check out the OWASP Top 10 and think about every part of the system. Where possible use existing libraries made by experts. If you have to roll your own, you're probably doing it wrong.

Related

Can I encrypt password on both frontend and backend?

I'm making an application that needs logging in.
I used node.js as API.
I understand I have to encrypt the password on backend in case the database is stolen.
But if for some reason HTTPS failed or some developer on our side had malicious intention he/she could easily steal the raw password if it wasn't encrypted on the frontend as well.
So my question is is there a problem if I use Argon2 on backend and BCrypt on frontend together?
(Also I assumed that Argon2 is faster so if the attacker wants to brute force he has to use the slow one as well on his side instead of my api heavylifting his/hers shannigans)
I know there are some simillar questions, but they ask if i should use one OR the other and the answer is backend and HTTPS.
I WILL use HTTPS and backend encryption. But I ask if it's possible (or a good idea) to use encryption on the frontend as well.
Argon2 and BCrypt are not encryption algorithms. They're password stretchers (formally "PBKDFs" or "Password-based Key Derivation Functions"). It doesn't make sense to use both, however.
The design you're looking for is this:
Apply a password stretcher on the front-end so that the raw password is never sent to the server.
On the backend, apply a fast hash (SHA-256) so that the hashed password is not stored in the database.
The first part protects the user. Their password never leaves their machine. The second part protects your database. Even if it's stolen, there's no way for an attacker to use the hashes stored there to log into your system.

Can https fallback to http and security level of https

I am considering installing SSL/TLS for my domain. There are two questions that have been bothering me:
Is there any scenario where a https connection can fallback to http? So, for e.g. if my ajax looks something like this
$.post("https://foo.com", function(){
});
Is there any chance this could change to
$.post("http://foo.com", function(){
});
and even if it does would my domain be still accesible at http://foo.com ?
Next I have read extensively about using SSL/TLS and from what I have read it seems to be fairly accurate to assume that if I have this enabled and even if I send the user credentials in plain text, it's still secure (There would be encryption with salt and everything on the server of course). To what extent is this true and would creating a hash on the client and then sending it over https be any more secure?
Update: If sending plaintext over SSL is secure enough, then what really is the point of using things like cnonce ? Isn't it just unnecessary overhead on the client?
No, HTTPS never falls back to HTTP automatically. It would take deliberate action by the user. If you're just going to a web page by putting its URL into the address bar, this is easy; for form submission it's harder.
Yes, sending plain text over SSL is fine. In fact, sending a hashed password doesn't really increase security much at all -- if someone manages to sniff the connection and gets the hashed password, that's all they need to be able to login to the site. It has one small advantage: if the user uses the same password at multiple sites, learning the hashed password for one site doesn't help them get into another site that uses a different (or no) hash. And it's not likely to be feasible to send salted hashes, since the client doesn't know the salt.
A cnonce adds an extra level of protection. If, somehow, someone manages to crack the SSL encryption, the cnonce prevents them from getting a usable password from it. This basically addresses the point I made above about why sending a hashed password doesn't help: what you need is something that changes from session to session, and a cnonce provides this.
See https://security.stackexchange.com/questions/3001/what-is-the-use-of-a-client-nonce

Proper way to send username and password from client to server

This question is not language specific. I'm curious how to properly send username and password from a website login form to a server.
My guess is to hash the password, put username/password in the POST body and send it over HTTPS. What's a better way?
For good measure I'll mention a less than ideal method:
http://www.somesite.com/login?un=myplaintextusername&pw=myplaintextpassword
The important parts are that you transmit the form data in the POST body (that way it's not cached anywhere, nor normally stored in any logfiles) and use HTTPS (that way, if you have a good SSL/TLS certificate, nobody can sniff out the password from observing your network traffic). If you do that, there is no big extra benefit in hashing the password, at least not during the transmission.
Why do people talk about hashing passwords, then? Because normally you don't want to store the user's password in plaintext form in your server-side database (otherwise the impact of a compromised server is even worse than it would be otherwise). Instead, you usually store a salted/hashed form, and then apply the same salt/hash to the password received via the form data, so that you can compare the two.
For more information on salting, see http://en.wikipedia.org/wiki/Salt_(cryptography) (and the links there).
If you're using HTTPS, then you can send the name and password in a POST body which will be secure from eavesdroppers (assuming you trust SSL). You don't need to hash the password, if you do then the password hash is just as useful as the password itself, so it doesn't buy you anything.
A more important question is how you store the password on the server side. Storing a hashed password is only acceptable if you use a good algorithm such as scrypt. But that's still not as good as an advanced protocol such as SRP.
You should always use HTTPS and avoid homebrewed code. SSL will take care of hashing & encryption. That is the ONLY secure method.
Also ensure you're hashing passwords on the server end and storing the hash, not the original password. Then compare the hashes to check logins. This will prevent attackers reading plaintext passwords straight out of your db if its compromised.

Security purpose

How to Encrypt Client side login before sending to server ?
You should use HTTPS.
Building security by yourself is hard, and you are very likely to get it wrong.
You should stick with the systems that the experts use.
On the server, remember to hash and salt the passwords, preferably using bcrypt.
There's one very simple solution. SSL. Ensure that all your login activities are served via https:// URLs.
The way that you do this, at least the "setting the server up" part vary depending on what web server you're using. You'd be better off asking a question of that nature on http://www.serverfault.com/
You can only use https - any client side encryption would be viewable on the client and therefore useless. There is SO question on this: password encryption at client side
You should really use HTTPS, but if you can't use HTTPS then the alternative is to create a hash.
Server generates a random 'salt' for the session
JavaScript on client-side creates a cryptographically secure hash of the user's password and the salt.
Hash is sent to the server, you can then retrieve the password from the database, create a hash using the salt for the session and the password from the DB and check if it is the same as the one sent from the client. - If it is then the password is a match.
An example of using JavaScript to protect passwords: http://pajhome.org.uk/crypt/md5/auth.html

Is it possible to hash a password and authenticate a user client-side?

I often make small websites and use the built in ASP.NET membership functionality in a SQL Server database, using the default "hashing" password storage method.
I'm wondering if there's a way to authenticate a user by hashing his password on the client and not sending it in clear text over the wire without using SSL.
I realize that this would only be applicable for users with Javascript enabled.
Or... possibly, this would be a great built-in capability for Silverlight (is this in the Silverlight roadmap?)
EDIT:
I'm also looking for "degrees of security." Meaning, if there is a method that has some advantages over simply sending plaintext password, I'd like to know what they are and why.
I know there are lots of people who do small sites with logins (such as a family website or volunteering to make a site for a local cooking club) and don't see the need for purchasing SSL certificates.
This is possible. This is actually what Kerberos authentication does, only with a little bit of added spice. To ensure that your authentication mechanism is secure, you need the following:
A common hashing algorithm on both the client and server.
A one-time salt value generated on the server and shared with the client.
The original password stored in a database.
To securely authenticate a user via hash code, so you avoid sending the actual password across the wire, first generate a random, single-use salt value on the server. Send this salt value to the client, and generate a hash code from the salted version of the password the user has input. Send the resulting hash code to the server, and compare it with a hash code generated from the salted version of the stored password. If the comparison fails, discard the salt, regenerate a new salt value, and repeat the process.
The reason for the single-use salt is to prevent anyone listening to the conversation from capturing the hash code of the users password, which, when you use hash code comparison, is just as good as having the password itself.
Note that you need to keep the original password around, you can't hash it once on the server and save the hash in the database. If you need to ensure that the passwords stored in your database are also secure, then you will need to encrypt them before storing them. I believe that ASP.NET membership providers do allow you to store passwords encrypted, however, if you really wish to have a secure authentication mechanism that is difficult for a hacker to crack, then I would recommend handling password storage and retrieval entirely on your own.
Finally, I should note, that such a complex password transfer mechanism should be largely unnecessary if you use SSL to encrypt your connection during authentication.
References (for those who have never heard of Kerberos or SRP):
http://en.wikipedia.org/wiki/Kerberos_(protocol)
http://en.wikipedia.org/wiki/Secure_remote_password_protocol
This is a bad idea, security wise. If you send a non-ssl form that contains the hashed password, then anyone capturing traffic has all they need to login. Your javascript has to result in something that indicates success (a redirect, token passed to the server, etc). Whatever it is, the listener now can recreate that without proper authentication.
SSL was built for a reason, by people who tried a lot of other web authentication schemes. It is far safer and cheaper to get a cert than to try write your own safe authentication scheme that works without encryption.
Added for clarity:
Client side hashing alone is not safe. Say I have a form with the following inputs
<form action="signin.whatever" method="post">
<input type="text" id="txtUser">
<input type="text" id="txtPass">
<input type="hidden" id="hiddenHash">
<input type="submit" onclick="hashAndSubmit()">
</form>
where hashAndSubmit() hashes the password and puts it in hiddenHash, and blanks out the password field. If I sniff your submission and see the following fields:
txtUser:joeuser
txtPass:
hiddenHash:xxx345yz // hash result
that's all I need as an attacker. I build a form with your user and hash value and I'm all set. The password is not necessary for a replay attack.
To get around this, you have to look at one-time salt values, or other schemes. All of which introduce more cost(don't forget developer time) and risk than SSL. Before you do something like this, ask one question...
Do I trust myself more than years and years of public testing of the SSL encryption?
You could do this, but it would be just as insecure. The problem is that someone could capture the hash and replay it (just as they could the original password). I suppose you're providing some protection against the exposure of the actual password (in case they use it on other systems), but your system will be no more secure.
You can implement your hashing algorithm client side (in javascript) and send only the user name and hash result over the wire. Note that in order for this to be secure the hash must be salted with a string provided by the server, and the string must be unique for every request. The sever still needs to check whether the hash is correct or not and authenticate the session.
At least you have to use a salt for generating the hash. Otherwise the hash value is as "valuable" as the plain password when intercepted - at least on your site.
You can send as post fields the username/realm/password hash following the HTTP Digest protocol. AFAIK there is no built-in client component nor server side component to generate/validate this so you have to do everything manually. It also requires your storage to store a specific hash format, see Storing password in tables and Digest authentication
The advantage is that you're following a well analyzed and understood authentication protocol. Don't roll your own.

Resources