What is the best practice for comparing passwords

When authenticating a user to a website, should hash generation and comparison be done in the database or on the website?

My argument is that the website should pass the user password (possibly encrypted by the web server) to the database. Then the database re-encrypts it with salt and compares the hash. The database responds to the web server whether the user credentials are valid or not. Thus, the smallest ever leaves the database, essentially either yes or no, none of the credentials stored. The disadvantage is that the database should work more.

Another argument is that the work should be done on a web server. Here the web server will create a hash and request the stored hash from the database and compare. In this situation, the salt must be transferred from the database back to the web server to create a hash. but the work is shared with the increase in the number of web servers.

Personally, I see the second method as a potential security risk. If the web server is compromised, salts and hashes can be requested from the database and easily hacked.

What is the best practice for performing the above operation? Am I missing / missing something?

thanks

+6
source share
4 answers

The first problem I suspect you will encounter (and it's big) is that your database does not have a password hash function. Of course, 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 means that LinkedIn passwords can be cracked so quickly. If you do not use one of the above functions, you will be vulnerable if your hashes leak.


Going further to answer your question, assuming your database supports a password hash algorithm (using bcrypt simply because I have to choose one). These two alternatives are:

Database hashing:

$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 connection can be encrypted. Hash and salt are never contained in the application.

Application hashing:

 $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 hash of the raw password and comparison is performed there. Communication with the database can still be encrypted. A raw password is never stored in database memory.

For efficiency, we can assume that both hashing algorithms are written in C (or in some compiled language) and may be provided by the OS, so take the same time. The hash option of the application receives more data over the wire, and the hash option of the database sends more and has a more complex request (essentially two requests, one for salt and the other for comparison). It may not be possible to use the index as I wrote this query, but the query can be rewritten. Since the data size in both cases is likely to remain a single TCP packet, the speed difference will be negligible. I would call it a win for hashing an application due to a subquery.

For exposure. I would find the raw password more sensitive than hash and salt. Therefore, limiting the impact of a raw password seems like a safer bet, which makes hashing a best practice.

+3
source

There's a really good article on how to safely store passwords here:

http://throwingfire.com/storing-passwords-securely/

+3
source

You ignore the purpose of the salt.

Salt is used to prevent a dictionary attack with hashed passwords. If your password is peanuts and hashed to 12345, I can pre-create a list of hashes for each word in the dictionary (including your password) and quickly find your password by searching my pre-created set of password hashes. Here's what happened to LinkedIn recently. If the passwords are salty, I will have to pre-generate a dictionary for each salt value after compromising the database, which would be too expensive.

In addition, the correct randomly generated salts do not allow an attacker to know that you and I have the same password (without salt, we will have the same hash).

My point is that salts are not for secrets. They are not publicly available information, but an attacker gaining access to salt values ​​+ hashes does not necessarily mean that passwords have been compromised.

+3
source

A good rule of thumb for computer security is that if you should ask, you should not do it yourself. But if your problem is with password information, if the web server is hacked, one approach is to transfer the authentication to your own system and not provide the web server with a password database at all.

0
source

Source: https://habr.com/ru/post/918200/


All Articles