Hashing of high-entropy application passwords - security

We want to add authentication via application passwords to out RESTful webservice. The application password will be a randomly generated string with high entropy (128bits or more). We need to check whether the application password is correct upon every request, i.e. the hashing of the password should be really fast - in contrast to usual password hashing where you want it to be rather slow.
So my question is: are there any security concerns using a fast hashing function? Any recommendations for a very fast but still "secure" hashing function?
Also, we are thinking of not using a salt either. There will practically never be two identical application passwords hence a salt doesn't seem to be necessary.

Related

Does it make sense to also hash password on frontend?

I'm aware passwords should be hashed/salted on backend and HTTPS should be used for transportation. My concern is that, on account registration, there is a section of code where the plain text password could exposed by way of a poorly placed log-statement.
I understand hashing passwords multiple times is not ideal, but to address this concern would it be acceptable (from a security governance perspective) to also hash the password on the frontend?
No, as password hashing should use salt and a suitable (slow) hashing algorithm, implementing this correctly and in the future double hash all passwords would require a lot more work than masking the password in the log.
If you use an unsalted hash with a fast hashing algorithm many passwords can be quickly broken using modern hash cracking equipment.
Also see Does it make security sense to hash password on client end

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.

Clientside password hashing

A friend of mine and me are having a discussion about whether we should pre-hash the passwords of the users of our webapp before sending it to our servers.
I know that there are multiple questions that already handle this topic but they're all about transferring it securely to the server. Our idea is not about the transfer security (we use SSL) we want to hash clientside to prevent that the "real" passwords reach our server.
The idea came as Twitter announced their bug that caused passwords to be printed to a logfile in cleartext.
We are currently discussing about whether this concept makes sense or not and how it affects the security of a password (in terms of Bruteforce) if we would hash it with SHA512.
TL;DR:
We want to hash passwords clientside to prevent our servers from getting them in cleartext (we use SSL for transfer).
Does this make any sense?
What algorithm would be best to use for hashing?
The hashed passwords would then serverside be hashed again with bCrypt.
It 100% makes sense: in fact, the concept has been proposed by a number of people, but the difficulty is in implementing correctly. There are a number of pitfalls if you do it wrong, the most direct one is being vulnerable to "pass-the-hash" as #swa66 describes. To prevent that, you need to hash on both sides. The client-side hash should be slow (bcrypt, scrypt, argon2, or pbkdf2) whereas the server side hash should be fast (sha256).
EDIT: A number of people have down-voted this without understanding how this works, so I now include the basic details here (previously I only linked to how this works). The idea is to apply a slow hash such as bcrypt on the client side, and then a fast hash such as SHA256 on the server side. The fast hash is required to prevent pass-the-hash attacks. In the event of the database leak, an attacker either hash to invert the fast hash (impossible -- violates the one-way property of a cryptographic hash function), or brute force the preimage to the fast hash (impossible -- the size is the length of the output from the slow hash, for example 184-bits for bcrypt), or brute force the combination of the slow hash and the fast hash -- which puts the attacker back at the same position as if the entire computation had happened server side. So we have not reduced the security of password attacks in the event of a database leak by shifting the heavy computation to the client side.
I've surveyed a number of proposals like this in Method to protect passwords in databases for web applications. Additionally, I analyse the pros and cons and identify weaknesses that have not been identified before (account enumeration), and propose a unique way of doing this securely. The research is built off a number of sources, including:
Secure authentication: partial client-side key stretching… please review/criticize my idea
How to securely hash passwords? -- see section on Client Side Hashing
Client side password hashing
Discussion from various authors on Hacker News -- see comments from oleganza, mschuster91, crusso, etc...
You cite the Twitter example, and GitHub did similarly. When I wrote the paper above, the most prominent example for preventing a server from seeing the clear text passwords was Heartbleed, which I comment on in the paper (bottom of Section 1.3).
There has been subsequent follow up research by others identifying similar ideas -- Example: Client-Plus-Server Password Hashing as a Potential Way to Improve Security Against Brute Force Attacks without Overloading the Server. No one person deserves all the credit, but the main takeaway is yes it is a good idea if you do it securely, but you really need to understand the risks (it is easy to do insecurely if you have not read the research).
While #swa66 outlined how to manage passwords securely, let me note that there is a valid scenario where you can consider client-side password hashing, so don't just blindly follow "best practice", try and understand it first.
Let's say I have a standard web application that stores data from users. In my threat model, I don't even want my own users to have to trust me, or in other words, I want my users' data to be secure even in case of a full compromise of my servers. Therefore, I let them choose a password, and encrypt their data on the client, before sending it to the application. They can retrieve their encrypted data with their user id. Well, that doesn't sound very secure, I can just download anybody's encrypted data and run offline attacks against it. So let's have them access their encrypted data with their password (I don't want them to have to remember two different passwords). But that's not good, because I have their password then to decrypt their data. So one simple solution is to encrypt their data with their password, and send it to the server along with their hashed password, which as it's correctly noted in the answer is the new password as far as the server is concerned (so the server should store it hashed once again and so on). However, the server has no way to decrypt client data, because it never has the original password, yet only the valid person can download even their encrypted stuff, and they only have to remember one password. (Note that this is a very much simplified model, in reality, much more is needed, like for example a proper key derivation function, not just plain hashes, but that's another, much longer story.)
Don't get me wrong, I'm not saying you should normally be hashing passwords on the client - no, the other answer is the correct one in that regard. I just wanted to show that there is at least one use-case where client-side password hashing is a valid option. See well-known password managers, some work similarly.
NO!
Rule one in cryptography: do not invent it yourself, you'll make horrible mistakes.
It's not against you personally, by far not: even top notch experts make mistakes when designing with great care new systems. That's why they peer-review each-other's work multiple times before anything become a standard. Many proposals for such standards by such experts get redrawn due to problems detected during such a peer-review. So why can't the rest of us mere mortals design: there's nobody good enough to do the peer-review as the experts will not touch it.
Hashing the password client side
Hashing client side is really bad as the hash becomes the password, and now you store it on the server in the clear.
How to do passwords
Only store hashed passwords (implied: send the password to the server, just do not store it)
use a salt and store it with the password (unencrypted). The salt is essentially a random string that you concatenate to the pasword before you hash it (to store it , and to verify it)
Use a SLOW hash. Using a fast hash is a common and fatal mistake, even when using salts. Most hash functions people know like SHA-256, SHA-3 etc. are fast hashes and completely unsuitable for hashing short, predictable items like passwords as they can be reversed in a surprising short time.
How slow: as slow as you can afford. Examples of slow hashes:
bcrypt, PBKDF-2 (which is essentially a high number of rounds of a
fast hash to make it slow)
There are -depending on your programming environment- pre-made routines, use them!
Ref:
https://crypto.stackexchange.com/questions/24/what-makes-a-hash-function-good-for-password-hashing
https://crypto.stackexchange.com/questions/59797/authorities-on-password-hashing-best-practice

What is the best practise for where password comparison should be performed

When authenticating a user to a website, should the hash generation and comparison be done in the database or the website?
My argument is the website should pass the user supplied password (possibly encrypted by the web server) to the database. The database then re-encrypts it with the salt and compares the hash's. The database the responds to the web server whether the user's credentials are valid or not. This way, the very minimum ever leaves the database, essentially either a yes or no, none of the stored credential info. Downside is, the database has to do more work.
The other argument is that the work should be done in the web server. Here the web server would create the hash and request the stored hash from the database and compare. In this situation the salt needs to be passed from the database back to the web server for the hash to be created. but, work is shared as # of web servers increase.
Personally I see the second method as a potential security risk. Should the web server be compromised, salts and hashes can be requested from the database and easily cracked.
What is the best practise for performing the above operation? Am I overlooking/missing something?
Thanks
The first problem I suspect you will run into (and it's a big one) is that your database does not have a password hash function. Sure, it probably has MD5() and SHA1() but these are cryptographic hash functions. Does it have bcrypt() or scrypt() or PBKDF2()?
Using a cryptographic hash function rather than a password hash function is what meant that the LinkedIn passwords could be cracked so quickly. If you don't use one of the above functions then you will be similarly vulnerable if your hashes are leaked.
Going on to answer your question assuming that your database does support a password hashing algorithm (using bcrypt simply because I have to pick one). The two alternatives are:
Hashing in the database:
$db->query("SELECT COUNT(*) FROM users WHERE username = '?' AND password = BCRYPT(?, (SELECT salt FROM user WHERE username = '?'))", $username, $password, $username);
if($row['count'] != 1)
{
// Not authenticated. Throw exception.
}
In this case, the raw password is sent to the database and a simple yes or no (1 or 0) is returned. This database communication can be encrypted. The hash and salt are never held in the application.
Hashing in the application:
$db->query("SELECT username, salt, password FROM users WHERE username = '?', $username);
if(bcrypt($password, $row['salt']) != $row['password'])
{
// Not authenticated. Throw exception.
}
In this case, the hash and salt are pulled from the database into the application and the hashing of the raw password and comparison is done there. The communication to the database can still be encrypted. The raw password is never held in the database memory.
For efficiency, we can assume that both hashing algorithms are written in C (or some compiled language) and are possibly provided by the OS so take the same time. The application hashing option receives more data over the wire and the database hashing option sends more and has a more complex query (essentially two queries, one to get the salt and one to effect the comparison). It may not be possible to use an index the way I have written that query but the query could be rewritten. Since the size of the data in both cases is likely still one TCP packet, the speed difference will be negligible. I would call this one a win for the application hashing option due to the subquery.
For exposure. I would consider the raw password to be more sensitive than the hash and the salt together. Therefore, limiting the exposure of the raw password seems like the safer bet, making application hashing the best practice.
There's a really good article on how to store passwords securely here:
http://throwingfire.com/storing-passwords-securely/
You are overlooking the purpose of a salt.
A salt is used to prevent a dictionary attack against hashed passwords. If your password is "peanut" and hashes to 12345, then I can pre-generate a list of hashes for every word in a dictionary (including your password) and quickly find your password by doing a lookup against my pre-generated set of password hashes. This is what happened to LinkedIn recently. If the passwords are salted, I'd have to pre-generate a dictionary for each salt value after compromising the database, which would be prohibitively expensive.
Furthermore, proper randomly-generated salts prevent an attacker from knowing that you and I have the same password (without the salt, we'd have the same hash).
My point is that the salts are not intended to be a secret. They are not public information, but an attacker getting access to the salt values + the hashes does not necessarily mean that the passwords have been compromised.
A good rule of thumb for computer security is that if you have to ask, you shouldn't do it yourself. But if your concern is exposure of password details if the web server is compromised, then one approach is to move authentication onto its own system, and don't give the web server access to the password database at all.

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.

Resources