Is Time() a Good Salt

Is time() a good salt?

Short answer:

No, time() is not a good salt.

Long answer:

copied from my answer to Salt Generation and open source software

What is a salt?


A salt is a random set of bytes of a fixed length that is added to the input of a hash algorithm.


Why is salting (or seeding) a hash useful?


Adding a random salt to a hash ensures that the same password will produce many different hashes. The salt is usually stored in the database, together with the result of the hash function.
Salting a hash is good for a number of reasons:

  1. Salting greatly increases the difficulty/cost of precomputated attacks (including rainbow tables)
  2. Salting makes sure that the same password does not result in the same hash.
    This makes sure you cannot determine if two users have the same password. And, even more important, you cannot determine if the same person uses the same password across different systems.
  3. Salting increases the complexity of passwords, thereby greatly decreasing the effectiveness of both Dictionary- and Birthday attacks. (This is only true if the salt is stored separate from the hash).
  4. Proper salting greatly increases the storage need for precomputation attacks, up to the point where they are no longer practical. (8 character case-sensitive alpha-numeric passwords with 16 bit salt, hashed to a 128 bit value, would take up just under 200 exabytes without rainbow reduction).


There is no need for the salt to be secret.


A salt is not a secret key, instead a salt 'works' by making the hash function specific to each instance. With salted hash, there is not one hash function, but one for every possible salt value. This prevent the attacker from attacking N hashed passwords for less than N times the cost of attacking one password. This is the point of the salt.

A "secret salt" is not a salt, it is called a "key", and it means that you are no longer computing a hash, but a Message Authentication Code (MAC). Computing MAC is tricky business (much trickier than simply slapping together a key and a value into a hash function) and it is a very different subject altogether.

The salt must be random for every instance in which it is used. This ensures that an attacker has to attack every salted hash separately.

If you rely on your salt (or salting algorithm) being secret, you enter the realms of Security Through Obscurity (won't work). Most probably, you do not get additional security from the salt secrecy; you just get the warm fuzzy feeling of security. So instead of making your system more secure, it just distracts you from reality.


So, why does the salt have to be random?


Technically, the salt should be unique. The point of the salt is to be distinct for each hashed password. This is meant worldwide. Since there is no central organization which distributes unique salts on demand, we have to rely on the next best thing, which is random selection with an unpredictable random generator, preferably within a salt space large enough to make collisions improbable (two instances using the same salt value).

It is tempting to try to derive a salt from some data which is "presumably unique", such as the user ID, but such schemes often fail due to some nasty details:

  1. If you use for example the user ID, some bad guys, attacking distinct systems, may just pool their resources and create precomputed tables for user IDs 1 to 50. A user ID is unique system-wide but not worldwide.

  2. The same applies to the username: there is one "root" per Unix system, but there are many roots in the world. A rainbow table for "root" would be worth the effort, since it could be applied to millions of systems. Worse yet, there are also many "bob" out there, and many do not have sysadmin training: their passwords could be quite weak.

  3. Uniqueness is also temporal. Sometimes, users change their password. For each new password, a new salt must be selected. Otherwise, an attacker obtained the hash of the old password and the hash of the new could try to attack both simultaneously.


Using a random salt obtained from a cryptographically secure, unpredictable PRNG may be some kind of overkill, but at least it provably protects you against all those hazards. It's not about preventing the attacker from knowing what an individual salt is, it's about not giving them the big, fat target that will be used on a substantial number of potential targets. Random selection makes the targets as thin as is practical.


In conclusion:


Use a random, evenly distributed, high entropy salt. Use a new salt whenever you create a new password or change a password. Store the salt along with the hashed password. Favor big salts (at least 10 bytes, preferably 16 or more).

A salt does not turn a bad password into a good password. It just makes sure that the attacker will at least pay the dictionary attack price for each bad password he breaks.



Usefull sources:
stackoverflow.com: Non-random salt for password hashes
Bruce Schneier: Practical Cryptography (book)

Matasano Security: Enough with the Rainbow Tables
usenix.org: Unix crypt used salt since 1976
owasp.org: Why add salt
openwall.com: Salts

Disclaimer:
I'm not a security expert. (Although this answer was reviewed by Thomas Pornin)

If any of the security professionals out there find something wrong, please do comment or edit this wiki answer.



As for what seems to be a good source for your random salt
Also read: What is the most secure seed for random number generation?
In the absence of dedicated, hardware based, random generators, the best way of obtaining random data is to ask the operating system (on Linux, this is called /dev/random or /dev/urandom [both have advantages and problems, choose your poison]; on Windows, call CryptGenRandom())

If for some reason you do not have access to the above mentioned sources of random, in PHP you could use the following function:

From the source of phpass v0.3

<?php
/**
* Generate pseudo random bits
* @copyright: public domain
* @link http://www.openwall.com/phpass/
* @param int $length number of bits to generate
* @return string A string with the hexadecimal number
* @note don't try to improve this, you will likely just ruin it
*/
function random_bits($entropy) {
$entropy /= 8;
$state = uniqid();
$str = '';
for ($i = 0; $i < $entropy; $i += 16) {
$state = md5(microtime().$state);
$str .= md5($state, true);
}
$str = unpack('H*', substr($str, 0, $entropy));
// for some weird reason, on some machines 32 bits binary data comes out as 65! hex characters!?
// so, added the substr
return substr(str_pad($str[1], $entropy*2, '0'), 0, $entropy*2);
}
?>

How strong do salts need to be?

The purpose of random salts is to ensure that a simple rainbow table won't work to decrypt the passwords, should the database table be leaked. If each record has its own salt, a new rainbow table would be needed for every single row.

Your shuffling approach is fine. The main point is for the salts to be DIFFERENT for each record, so that a single rainbow table won't compromise the whole table of passwords. The "strength" of the salts isn't as important.

Is it safer to have the salt in the source code?

Definitely use new salt for each password and store them in the database alongside the passwords. Please see https://en.wikipedia.org/wiki/Salt_(cryptography)#Common_mistakes for reasons. If you want to learn more about the topic, the whole wikipedia article is a great source, followed by https://en.wikipedia.org/wiki/Rainbow_table, maybe even some generic info about hashing like https://en.wikipedia.org/wiki/Cryptographic_hash_function.

Is it a good idea to update hash salt every login?

No, it makes no sense at all.

The purpose of salting hashes is to make them unique even if the original password is the same. This avoids e.g. rainbow table attacks or re-using a stolen hash on another website where the hash is sufficient to login (happens with bad remember-me implementations).

Assume an attacker got the stored password hash from your database. This usually means that he knows both the salt and the final hash. Now he can already brute-force this single password. Assuming there are no collisions he'll end up with the actual password of the user when the brute-force attack succeeds. And that one will work no matter what salt is used at this moment.

For more information about salting I suggest you to read this excellent answer on IT Security

Non-random salt for password hashes

Salt is traditionally stored as a prefix to the hashed password. This already makes it known to any attacker with access to the password hash. Using the username as salt or not does not affect that knowledge and, therefore, it would have no effect on single-system security.

However, using the username or any other user-controlled value as salt would reduce cross-system security, as a user who had the same username and password on multiple systems which use the same password hashing algorithm would end up with the same password hash on each of those systems. I do not consider this a significant liability because I, as an attacker, would try passwords that a target account is known to have used on other systems first before attempting any other means of compromising the account. Identical hashes would only tell me in advance that the known password would work, they would not make the actual attack any easier. (Note, though, that a quick comparison of the account databases would provide a list of higher-priority targets, since it would tell me who is and who isn't reusing passwords.)

The greater danger from this idea is that usernames are commonly reused - just about any site you care to visit will have a user account named "Dave", for example, and "admin" or "root" are even more common - which would make construction of rainbow tables targeting users with those common names much easier and more effective.

Both of these flaws could be effectively addressed by adding a second salt value (either fixed and hidden or exposed like standard salt) to the password before hashing it, but, at that point, you may as well just be using standard entropic salt anyhow instead of working the username into it.

Edited to Add: A lot of people are talking about entropy and whether entropy in salt is important. It is, but not for the reason most of the comments on it seem to think.

The general thought seems to be that entropy is important so that the salt will be difficult for an attacker to guess. This is incorrect and, in fact, completely irrelevant. As has been pointed out a few times by various people, attacks which will be affected by salt can only be made by someone with the password database and someone with the password database can just look to see what each account's salt is. Whether it's guessable or not doesn't matter when you can trivially look it up.

The reason that entropy is important is to avoid clustering of salt values. If the salt is based on username and you know that most systems will have an account named either "root" or "admin", then you can make a rainbow table for those two salts and it will crack most systems. If, on the other hand, a random 16-bit salt is used and the random values have roughly even distribution, then you need a rainbow table for all 2^16 possible salts.

It's not about preventing the attacker from knowing what an individual account's salt is, it's about not giving them the big, fat target of a single salt that will be used on a substantial proportion of potential targets.

Does a Good Password Salt Need to Include Both Numbers and Letters?

A salt should be unique (ideally for every password in the world), and unpredictable. The best you can do with a deterministic computer is, to get a random number, and hope that the returned value is nearly unique. So the more possible combinations you have, the bigger is the chance that the salt is unique.

Some hash algorithms define a number and an alphabet of accepted characters. PHP's BCrypt for example, expects a salt containing 22 characters from this alphabet:

./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

You get the most possible combinations, using all characters of the alphabet, and not only the characters 0-9. Of course a longer salt with a small alphabet (0-9) can have as much combinations, as a shorter salt with a big alphabet (0-9,a-z,...).

To make it short, use all possible characters, and as many characters as your hash algorithm expects.

P.S: If you use a key-derivation function like BCrypt (and you really should), then you cannot salt the password befor hashing, instead you have to pass the salt to the hash function.

How unique is the salt produced by this function?

to a first approximation they are not going to collide! in fact I'd suggest making length smaller so you don't potentially reveal as much entropy of the RNG

your algorithm currently produces log2(256**94) = 8*94 = 752 random bits. via the birthday problem we know that you'd have to produce 2**(752/2) = 2376 values to have a 50% chance of collision. generating this many values is impossible.

lets reduce this down to a more reasonable 2128 lifetime chance of collision. this means you'd want 256 random bits generated, and would mean your length would be 256/8 = 32.

note that all of the above relies upon Random.secure actually being a csPRNG and any attacker not knowing any of its state. given the above probabilities, this is the much bigger vulnerability of this system



Related Topics



Leave a reply



Submit