ChatGPT解决这个技术问题 Extra ChatGPT

The necessity of hiding the salt for a hash

At work we have two competing theories for salts. The products I work on use something like a user name or phone number to salt the hash. Essentially something that is different for each user but is readily available to us. The other product randomly generates a salt for each user and changes each time the user changes the password. The salt is then encrypted in the database.

My question is if the second approach is really necessary? I can understand from a purely theoretical perspective that it is more secure than the first approach, but what about from a practicality point of view. Right now to authenticate a user, the salt must be unencrypted and applied to the login information.

After thinking about it, I just don't see a real security gain from this approach. Changing the salt from account to account, still makes it extremely difficult for someone to attempt to brute force the hashing algorithm even if the attacker was aware of how to quickly determine what it was for each account. This is going on the assumption that the passwords are sufficiently strong. (Obviously finding the correct hash for a set of passwords where they are all two digits is significantly easier than finding the correct hash of passwords which are 8 digits). Am I incorrect in my logic, or is there something that I am missing?

EDIT: Okay so here's the reason why I think it's really moot to encrypt the salt. (lemme know if I'm on the right track).

For the following explanation, we'll assume that the passwords are always 8 characters and the salt is 5 and all passwords are comprised of lowercase letters (it just makes the math easier).

Having a different salt for each entry means that I can't use the same rainbow table (actually technically I could if I had one of sufficient size, but let's ignore that for the moment). This is the real key to the salt from what I understand, because to crack every account I have to reinvent the wheel so to speak for each one. Now if I know how to apply the correct salt to a password to generate the hash, I'd do it because a salt really just extends the length/complexity of the hashed phrase. So I would be cutting the number of possible combinations I would need to generate to "know" I have the password + salt from 13^26 to 8^26 because I know what the salt is. Now that makes it easier, but still really hard.

So onto encrypting the salt. If I know the salt is encrypted, I wouldn't try and decrypt (assuming I know it has a sufficient level of encryption) it first. I would ignore it. Instead of trying to figure out how to decrypt it, going back to the previous example I would just generate a larger rainbow table containing all keys for the 13^26. Not knowing the salt would definitely slow me down, but I don't think it would add the monumental task of trying to crack the salt encryption first. That's why I don't think it's worth it. Thoughts?

Here is a link describing how long passwords will hold up under a brute force attack: http://www.lockdown.co.uk/?pg=combi

Good question, Kevin, very timely. I can't comment on security, but there is a performance hit for all this encrypting and decrypting, for sure.
You don't need to ignore the rainbow table of decent size - that table also makes the encrypted salt moot since it can decrypt the salted hash and be used again to decrypt the original hash. The good news is that table would take probably centuries to create.
The thing that gets me is that I'm not totally certain a rainbow table of that size would take that long to create. He is a wacky idea, take a distributed computing platform like Kraken (really that's kinda what it is) to generate it. How long would it take then?
@Kevin: SHA1 returns a 40-character hex string, so there are 40^16 possible return values. Assuming a single computer can calculate 1000 hashes every second I calculate 1 000 000 computers would take about 10 billion years to generate a rainbow table capable of determining a string that size.
@tloach There are software that can do peaks 5600M/s MD5 hashes and 2300M/s SHA1 hashes. golubev.com/hashgpu.htm

e
erickson

Hiding a salt is unnecessary.

A different salt should be used for every hash. In practice, this is easy to achieve by getting 8 or more bytes from cryptographic quality random number generator.

From a previous answer of mine:

Salt helps to thwart pre-computed dictionary attacks. Suppose an attacker has a list of likely passwords. He can hash each and compare it to the hash of his victim's password, and see if it matches. If the list is large, this could take a long time. He doesn't want spend that much time on his next target, so he records the result in a "dictionary" where a hash points to its corresponding input. If the list of passwords is very, very long, he can use techniques like a Rainbow Table to save some space. However, suppose his next target salted their password. Even if the attacker knows what the salt is, his precomputed table is worthless—the salt changes the hash resulting from each password. He has to re-hash all of the passwords in his list, affixing the target's salt to the input. Every different salt requires a different dictionary, and if enough salts are used, the attacker won't have room to store dictionaries for them all. Trading space to save time is no longer an option; the attacker must fall back to hashing each password in his list for each target he wants to attack. So, it's not necessary to keep the salt secret. Ensuring that the attacker doesn't have a pre-computed dictionary corresponding to that particular salt is sufficient.

After thinking about this a bit more, I've realized that fooling yourself into thinking the salt can be hidden is dangerous. It's much better to assume the salt cannot be hidden, and design the system to be safe in spite of that. I provide a more detailed explanation in another answer.

However, recent recommendations from NIST encourage the use of an additional, secret "salt" (I've seen others call this additional secret "pepper"). One additional iteration of the key derivation can be performed using this secret as a salt. Rather than increasing strength against a pre-computed lookup attack, this round protects against password guessing, much like the large number of iterations in a good key derivation function. This secret serves no purpose if stored with the hashed password; it must be managed as a secret, and that could be difficult in a large user database.


Hiding the salt is necessary because the hash cannot be broken until it is obtained. This is related to CWE-760 (cwe.mitre.org/data/definitions/760.html)
@The Rook - No, you are misinterpreting that issue. It refers to the use of predictable salts. It does not say anything about keeping the salt secret. Indeed, you can't really keep the salt secret without using another secret... in which case, why wouldn't you use the second secret as the salt? Using the username as a salt is bad because its likely that multiple systems share the same username, making it more worthwhile to build a table for that particular salt. Random salts are best, but they do not need to be kept secret.
@erickson, I think you are mixing up terminology here. Salts do not thwart dictionary attacks unless they are hidden. Alot of salts are stored openly. And if you know the salt, you're dictionary attack is only slowed by the time it takes to append the salt to your dictionary term :) Salts prevent Rainbow table look ups.... which are pretty darn fast. If the attacker knows your salt, you are not protected from a dictionary attack. If the attacker does not know your salt though, you are protected from a dictionary attack and they must use a brute force attack.
@Ultratrunks Yes, I have clarified some of my answers on this topic, using the term "pre-computed dictionary attacks." More general than Rainbow tables, it refers to any structure that allows a reverse lookup of a plaintext using its hash as a key. Regardless of the terms you choose, my explains explicitly that salt is intended to defeat Rainbow tables and similar mechanisms. You should always assume the attacker knows the salt. If it were possible to keep it secret, you wouldn't need to hash the password.
V
Vinko Vrsalovic

The answer here is to ask yourself what you're really trying to protect from? If someone has access to your database, then they have access to the encrypted salts, and they probably have access to your code as well. With all that could they decrypt the encrypted salts? If so then the encryption is pretty much useless anyway. The salt really is there to make it so it isn't possible to form a rainbow table to crack your entire password database in one go if it gets broken into. From that point of view, so long as each salt is unique there is no difference, a brute force attack would be required with your salts or the encrypted salts for each password individually.


Kinda new to these concepts. So, it might look like a naive question but wouldn't it be easier to form that rainbow table with knowing the salt for each password as you would try only one combination for the salt value for every possible password?
ranbow table from say 1000 commonly used passwords would break this in almost the same speed as just hashing. The only way this would work is that if you assume the distribution of your passwords to be uniform.. and we know they are not
No, it's not that likely that they have access both to the database and the source code, and the source code should not contain the application secret used for encryption. Consider an attack vector of SQL injection, or an exposed backup database. Those don't grant access to either code or encryption keys.
C
Community

A hidden salt is no longer salt. It's pepper. It has its use. It's different from salt.

Pepper is a secret key added to the password + salt which makes the hash into an HMAC (Hash Based Message Authentication Code). A hacker with access to the hash output and the salt can theoretically brute force guess an input which will generate the hash (and therefore pass validation in the password textbox). By adding pepper you increase the problem space in a cryptographically random way, rendering the problem intractable without serious hardware.

For more information on pepper, check here.

See also hmac.


g
gbarry

My understanding of "salt" is that it makes cracking more difficult, but it doesn't try to hide the extra data. If you are trying to get more security by making the salt "secret", then you really just want more bits in your encryption keys.


B
Bill the Lizard

The second approach is only slightly more secure. Salts protect users from dictionary attacks and rainbow table attacks. They make it harder for an ambitious attacker to compromise your entire system, but are still vulnerable to attacks that are focused on one user of your system. If you use information that's publicly available, like a telephone number, and the attacker becomes aware of this, then you've saved them a step in their attack. Of course the question is moot if the attacker gets your whole database, salts and all.

EDIT: After re-reading over this answer and some of the comments, it occurs to me that some of the confusion may be due to the fact that I'm only comparing the two very specific cases presented in the question: random salt vs. non-random salt. The question of using a telephone number as a salt is moot if the attacker gets your whole database, not the question of using a salt at all.


How do they protect against dictionary attacks?
By forcing the attacker to make a new dictionary for each password+salt combination. Without salt, one dictionary can be used against your whole passwords table.
"Of course the question is moot if the attacker gets your whole database, salts and all." Isn't that why the salt is encrypted?
@Bill: You just described a rainbow table. A dictionary attack is where I take normal words and attempt to authenticate with them. It's a brute-force with a greatly reduced answer space. No hash defends against brute force.
I've never heard of this practice, but I'm not a security expert. It seems like encrypting unique salts would add an extra layer of protection against rainbow table attacks.
A
Anon

... something like a user name or phone number to salt the hash. ... My question is if the second approach is really necessary? I can understand from a purely theoretical perspective that it is more secure than the first approach, but what about from a practicality point of view?

From a practical point of view, a salt is an implementation detail. If you ever change how user info is collected or maintained – and both user names and phone numbers sometimes change, to use your exact examples – then you may have compromised your security. Do you want such an outward-facing change to have much deeper security concerns?

Does stopping the requirement that each account have a phone number need to involve a complete security review to make sure you haven't opened up those accounts to a security compromise?


Not to mention if you're using some arbitrary bit of user information, when they change that information you need them to input their password again so you can encrypt it again with the new salt.
C
Charles Faiga

Here is a simple example showing why it is bad to have the same salt for each hash

Consider the following table

UserId  UserName,   Password
     1  Fred       Hash1 =  Sha(Salt1+Password1)    
     2  Ted        Hash2 =  Sha(Salt2+Password2)    

Case 1 when salt 1 is the same as salt2 If Hash2 is replaced with Hash1 then user 2 could logon with user 1 password

Case 2 when salt 1 not the same salt2 If Hash2 is replaced with Hash1 then user2 can not logon with users 1 password.


We're not using the same hash for each account, we're using the same type of information for each hash. For example, the salt for an account is the account's phonenumber etc.
I know this is a long time later, but... you cannot rely on salts to protect against this type of attack. We must assume than an attacker knows everything about the authentication system other than the secret (i.e. password). Therefore we must assume that the attacker knows a) what we are using as the salt (most times this is stored in the same database & table in plaintext) and b) how we are hashing with the salt (i.e. appending, hashing-twice, etc). If the user has the ability to switch the hashes then we must assume they can also switch the salt. Salts will not help here.
P
Patrick McElhaney

There are two techniques, with different goals:

The "salt" is used to make two otherwise equal passwords encrypt differently. This way, an intruder can't efficiently use a dictionary attack against a whole list of encrypted passwords.

The (shared) "secret" is added before hashing a message, so that an intruder can't create his own messages and have them accepted.


R
Russell Hankins

I tend to hide the salt. I use 10 bits of salt by prepending a random number from 1 to 1024 to the beginning of the password before hashing it. When comparing the password the user entered with the hash, I loop from 1 to 1024 and try every possible value of salt until I find the match. This takes less than 1/10 of a second. I got the idea to do it this way from the PHP password_hash and password_verify. In my example, the "cost" is 10 for 10 bits of salt. Or from what another user said, hidden "salt" is called "pepper". The salt is not encrypted in the database. It's brute forced out. It would make the rainbow table necessary to reverse the hash 1000 times larger. I use sha256 because it's fast, but still considered secure.


So if my password is "345678" and the random salt you prepend happens to be, say, "12". If someone enters "45678" as my password. This seems wrong in many ways.
I guess Russell Hankins meant prepending a random number from 1 to 1024, formatted with zeroes on the left; that is, if the random salt is 12, you prepend with "0012"
L
Lucas Oman

Really, it depends on from what type of attack you're trying to protect your data.

The purpose of a unique salt for each password is to prevent a dictionary attack against the entire password database.

Encrypting the unique salt for each password would make it more difficult to crack an individual password, yes, but you must weigh whether there's really much of a benefit. If the attacker, by brute force, finds that this string:

Marianne2ae85fb5d

hashes to a hash stored in the DB, is it really that hard to figure out what which part is the pass and which part is the salt?


If someone brute forces such an impossible to guess password, I'd say you're hosed anyway, because apparently they have technology no one has even thought of yet.