Password hashing at client browser - security

What's the best way to hash the user password at the client browser, before sending it to the web server, so that only the hash goes out, not the plain-text password?
EDIT: assuming HTTP is used (not HTTPS)

Use javascript to calculate the hash. See this for an example on how to calculate SHA-1 hashes in JS.
Beware that if you make yourself dependant on Javascript, your system will fail as soon as someone has JS disabled. You should use HTTPS if this is a concern to you, which has its own setbacks (e.g. certificates cost money if you want them to be immediately accepted by browsers.)

Try using this jQuery encryption plugin. Out of curiosity, what's wrong with using SSL/HTTPS and encrypting at the server side?

Not all people have JavaScript enabled in their browsers and even the idea of sending hashes on a plain-text channel I think is not secure enough.
I would recommend you to consider a SSL secured connection.

This site has quite comprehensive hashing/crypto stuff: JavaScript Encryption Library

JavaScript side encryption like the jQuery Encryption library stops Eavesdroppers. However, MITM (Man-in-the-Middle) can still occur. SSL/TLS is the ultimate choice that is highly recommended to take unless you are on shared hosting (no dedicated IPs) or your site is receiving so much traffic that you can't simply encrypt all connections (JS, CSS, HTML, ...).

Why would you bother doing this? Effectively, the password hash has become the password and a a man-in-the-middle who intercepts the hash can use it to authenticate and perform any action as the user. On the other hand, if you don't believe in the man-in-the-middle, why not just send the password itself?

Why do we hash passwords? So that if the hashes are obtained they're difficult to use.
What happens in this model if the hashes in the system are exposed? The attacker simply sends them to the server and authenticates as the user.
This is why password hashing always happens on the server, not the client!

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.

Best Practice - Encrypt password even when sending through https?

I apologize if this has been asked before but I am hoping for an up-to-date answer.
I am very new to server-side security and I want to do this correctly.
My question: Is it best-practice to encrypt a password that is being sent over HTTPS?
I have seen posts that recommend using Javascript to encrypt a password before it is sent in the POST variables but I am not sure if this is necessary when using HTTPS.
Please note: I have every intention of hashing & salting the password when it is stored in the database.
If using HTTPS, there isn't much of a reason to encrypt data sent between client and server. HTTPS does that for you, so any further encryption is redundant.
The only reason I can think of to encrypt the password in advance would be to hash it client side to avoid having the clear password persist in server memory or logs. This is somewhat paranoid, and probably not of much use in the real world. Logs should never record passwords regardless, and if someone has access to your server memory, you've got other issues to contend with besides for password encryption.
Also, encrypting the password in the client allows others to see how the encryption/hashing is being performed. IMHO that is more of a security risk than having it reside in server memory for a few ms.

Which attacks are possible concerning my security layer concept?

Despite all the advices to use SSL/https/etc. I decided to implement my own security layer on top of http for my application... The concept works as follows:
User registers -> a new RSA Keypair is generated
the Private Key gets encrypted with AES using the users login Password
(which the server doesnt know - it has only the sha256 for authentication...)
Server stores the hash of the users password
and the Encrypted Private Key and Public Key
User logs in -> authenticates with nickname+password hash
(normal nick/password -> IP-bound sessionid authentication)
Server replies: sessionid, the Encrypted RSA Private Key
and an Encrypted randomly generated Session Communication Password
Client decrypts the RSA Private Key with the users Password
Client decrypts the Session Communication Password with the RSA Private Key
---> From this point on the whole traffic gets AES-encrypted
using that Session Password
I found no hole in that chain - neither the private key nor the login password get ever sent to the server as plaintext (I make no use of cookies, to exclude the possibility of the HTTP Cookie header to contain sensitive information)... but I am biased, so I ask - does my security implementation provide enough... security?
Why does everyone have to come up with their secure transport layer? What makes you think you've got something better than SSL or TLS? I simply do not understand the motivation to re-invent the wheel, which is a particularly dangerous thing to do when it comes to cryptography. HTTPS is a complex beast and it actually does a lot of work.
Remember, HTTPS also involves authentication (eg: being able to know you are actually talking to who you think you are talking to), which is why there exists a PKI and browsers are shipped with Root CA's. This is simply extremely difficult (if not impossible) to re-invent and prone to security holes. To answer you question, how are you defending against MITM attacks?
TLDR: Don't do it. SSL/TLS work just fine.
/endrant.
I'm not a crypto or security expert by any means, but I do see one serious flaw:
There is no way the client can know that it is running the right crypto code. With SSL/TLS there is an agreed upon standard that both your browser vendor and the server software vendor have implemented. You do not need to tell the browser how SSL works, it comes built in, and you can trust that it works correctly and safely. But, in your case, the browser only learns about the correct protocol by receiving plain-text JavaScript from your server.
This means that you can never trust that the client is actually running the correct crypto code. Any man-in-the-middle could deliver JavaScript that behaves identically to the script you normally serve, except that it sends all the decrypted messages to the attacker's servers. And there's no way for the client to protect against this.
That's the biggest flaw, and I suspect it's a fatal flaw for your solution. I don't see a way around this. As long as your system relies on delivering your crypto code to the client, you'll always be susceptible to man-in-the-middle attacks. Unless, of course, you delivered that code over SSL :)
It looks like you've made more complexity than is needed, as far as "home-grown" is concerned. Specifically, I see no need to involve assymetric keys. If the server already knows the user's hashed password, then just have the client generate a session id rolled into a message digest (symmetrically) encrypted via the client's hashed password.
The best an attacker might do is sniff that initial traffic, and attempt a reply attack...but the attacker would not understand the server's response.
Keep in mind, if you don't use TLS/SSL, then you won't get hardware-accelerated encryption (it will be slower, probably noticeably so).
You should also consider using HMAC, with the twist of simply using the user's password as the crypto key.
SSL/TLS provide transport layer security and what you've done does nothing but do that all over again for only the authorization process. You'd be better served to focus on authorization techniques like client certificates than to add an additional layer of line-level encryption. There's a number of things you could also introduce that you haven't mentioned such as encrypted columns in SQL Server 2008, IPSec, layer 4 & 7 hardware solutions and even setting up trusts between the server and client firewalls. My biggest concern is how you've created such a deep dependency on the username and password, both which can change over time in any system.
I would highly recommend that you reconsider using this approach and look to rely on more standard techniques for ensuring that credentials are never stored unencrypted on the server or passed in the clear from the client.
While I would also advocate the use of SSL/TLS for this sort of thing, there is nothing wrong with going re-inventing the wheel; it leads to innovation, such as the stack exchange series of websites.
I think your security model is quite sufficient and rather intelligent, although what are you using on the client-side? I'm assuming javascript since you tagged this post with 'web-development'? Or are you using this to communicate with a plug-in of sorts? How much overhead does your implementation produce?
Some areas of concern:
-How are you handling initial communication, such as: user login, registration?
-What about man-in-the-middle attacks (assuring the client that it is talking to the authorized server)?
The major problem you have is that your client crypto code is delivered as Javascript over unauthenticated HTTP.
This gives the Man-In-The-Middle plenty of options. He can modify the code so that it still authenticates with your server, but also sends the password / private key / plaintext of the conversation to him.
Javascript encryption can be enough when your adversary is an eavesdropper that can see your traffic but not modify it.
Please note that I am not referring to your specific idea (which I did not take the time to fully understand) but to the general concept of Javascript encryption.

Does it make security sense to hash password on client end

If you were to hash a user's password prior to sending it across the line and leaving it in plain-text in memory, would this improve the security of the application?
I would assume this mitigates a small fraction of vulnerabilities by protecting the data stored in the clients memory. But really if we're worried about someone reading the client's memory there are probably bigger problems that we can't address.
There's something that doesn't feel right about hashing on the client's end.
Is password hashing on the client end a common practice? Are there any other advantages or disadvantages to doing it?
EDIT:
Given the communication channel is secure (SSL). Under what conditions would it be acceptable and worthwhile to use such an approach. I'm asking this because it was suggested by a "security professional" that I use such a scheme during some application functions.
No.
When the client sends something, whether it is P or H(P) or H(H(P)) anyone who intercepts this can simply resend the exact same thing, thus making any function like this equivalent to using the password directly.
That's why you should use a nonce; The server can give out some random garbage k and the client will calculate H(P,k) and send it to the server. HMAC is a popular implementation of this method.
Provided the server never accepts the same nonce twice, this is secure against a replay attack.
Sending a hashed password won't improve security on your site, as others have pointed out (since you accept a hashed password, all the bad guy needs to know is the hashed version). It's also not really secure, since the bad guy can presumably load your login page and examine the Javascript or Java deployed.
What it does do is prevents somebody watching the packets from being able to pull out a password, and that is moderately useful. Many people use the same password on multiple sites (I do it for all but the higher security sites), and therefore if you can get one password from them you can log into other accounts on other sites.
It also prevents the real password from being stored, even temporarily, on your site, and that may provide a little extra security if your site is compromised.
So, while I'd consider user-side hashing to be potentially a good things, it isn't worth going to much extra trouble.
And, as others have told you, don't roll your own security. There's far too many things that can go wrong. You won't notice them nearly as fast as a practiced bad guy will.
The hash is identical to the password from a security POV in the scenario you describe: if I intercept the hash, I don't need to know the password, I can just send the server the hash I intercepted.
Authentication protocols go to some length to avoid this problem; security is hard, and you are best off selecting and implementing a well-understood protocol rather than rolling your own.
If your traffic is going over SSL, you're safe from interception and hashing gives you little extra benefit.
Yes, you should.
IEEE had a data breach in which 100K emails and passwords were exposed from a weblog.
http://ieeelog.com/
Obviously, IEEE should not have exposed their weblog! But if they had hashed the passwords at the client side, this wouldn't have been nearly as bad.
As the first answer states, you should use a nonce. If you use a long enough nonce (e.g. 128 bits), you don't really need to worry about reuse, as the server will never ask for the same nonce twice (assuming correctly seeded CRNG, etc.).
No, hashing at the client does not protect the password 'completely'. When one opts to hash the password at the client, then the digest submitted to the server, essentially becomes the password. This is not a problem in itself if SSL is deployed.
However, this scheme ends up creating more problems than it solves. If the server were to compare the hash submitted by the client with a stored hash in the database without performing any further cryptographic operations (especially hashing the input data), then the password is stored in clear text for all practical purposes. Any person with access to the stored hash can re-submit it to the server and gain access to accounts.
In simple terms, if the submitted hash (which is the same as the submitted hash) were to leak via any other vulnerability within the application (via SQL injection, for instance) then the application has a vulnerability where in it protects the passwords inadequately.
If the underlying vulnerability must be fixed, then it is necessary to treat the submitted hash as a password in clear text, which should then be hashed (with a salt preferably) before comparison with a stored hash.
I think it makes sense in one circumstance; you don't want to even know the client's plaintext password. If you hash at the client side, then salt and iteratively hash that hash the same way you would a plaintext pw. Other than that, its kinda silly.
Just make sure that you are sending your password through a secure channel (SSL). If the client can have an application private memory read, then most likely they have bigger problems, like for example a keylogger.
You'd be much better off if you used the Secure Remote Password protocol (SRP). It was designed for this.
I can give you different kind of approach
If you have not SSL you can hash password on client side and again it hashed on server side using another hashing method and store them on database
and when user login with password do the same process and match double hashed password with stored hashes
Yes it makes sense to hash the password on the client side even if you use SSL but still you must also hash it again on the server side.
This makes sense especially in case of a mobile app. If you hash on the client side even with a "constant salt"/domain string it will be much better than sending a password in plaintext even if you use SSL. If you send plaintext passwords to the server then in case someone hacks your server he will receive password in plaintext. So adding additional pre hashing on client side protects the users and their password which they probably use also in other places.
You will probably find many posts saying that client side hashing is not needed but they usually are related to a web apps and do not consider mobile app case. In case of a web app if someone hacks the server he can replace the website and remove the client side hashing anyway so in such case there is not that big advantage. But for mobile apps an attacker cannot replace code of the mobile app so hashing on the client side has a lot of sense in such case.
You can check this link for a possible solution with hashing on both client and server side: https://medium.com/#harwoeck/password-and-credential-management-in-2018-56f43669d588
So yes, hash on both client and server side.
Hashing on the client side opens up another huge hole: you may expose the hashing algorithm. You don't say whether this is web-based (client=JavaScript) or thick-client, but you're giving them more information. Given the channel is secure, you don't have to worry about the clear text password being sniffed.
Besides, if your hashing algorithm requires a salt, you would be exposing your salt, which means if they ever got access to the database, they would be able to decrypt every password.

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