Improve Password Hashing with a Random Salt

Improve password hashing with a random salt

An attacker is "allowed" to know the salt - your security must be designed in a way that even with the knowledge of the salt it is still secure.

What does the salt do ?

Salt aids in defending against brute-force attacks using pre-computed "rainbow-tables".

Salt makes brute-force much more expensive (in time/memory terms) for the attacker.

Calculating such a table is expensive and usually only done when it can be used for more than one attack/password.

IF you use the same salt for all password an attacker could pre-compute such a table and then brute-force your passwords into cleartext...

As long as you generate a new (best cryptogrpahically strong) random salt for every password you want to store the hash of there is no problem.

IF you want to strengthen the security further

You could calculate the hash several times over (hash the hash etc.) - this doesn't cost you much but it makes a brute-force attack / calculating "rainbow-tables" even more expensive... please don't invent yourself - there are proven standard methods to do so, see for example http://en.wikipedia.org/wiki/PBKDF2 and http://www.itnewb.com/tutorial/Encrypting-Passwords-with-PHP-for-Storage-Using-the-RSA-PBKDF2-Standard

NOTE:

Using such a mechanism is these days mandatrory since "CPU time" (usable for attacks like rainbow tables/brute force etc.) is getting more and more widely available (see for example the fact that Amazon's Cloud service is among the top 50 of fastest supercomuters worldwide and can be used by anyone for a comparatively small amount)!

How does password salt increase security

What I do not understand is what hinders an automated function to chose a username and just make a lot of login attempts on - for example - a web site, with different password each time. To me it would seem that the salt has no function in that scenario?

Correct. Hashing and salting do not prevent against brute-force login attempts. (For that, you want to limit the number of login attempts per unit of time, or to ban after X-failed attempts).

Hashing and salting are used to prevent a stolen password list being cracked (or, to increase the amount of time needed to crack said list).

When storing passwords, you have 3 options: plain text, hashed, or hashed+salted. If I steal your password list:

  • Plain text: I now have the login details for all your users. I can impersonate them. (That's bad).
  • Hashed: I can use a rainbow table to determine the password from the hash reasonably quickly. (That's also bad).
  • Hashed + salted: Now the rainbow tables don't work. I have to spend considerably more time cracking each password. It's still possible, but it is a lot harder (and, unless you're actually important, I'm probably not going to bother). Note that this also gives you time to notice the security breech and inform your customers their passwords were stolen, and ask them to change it (so even when I eventually crack the hashed+salted list, I can't use it).

So: hashing + salting is used to prevent (or slow) attempts to crack a password from a stolen hash using brute force methods.

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 rehashing a randomly salted password at login increase security?

I don't think it will increase security, no. You have two risk scenarios:

  • The cracker breaks into a server and stays there for some time undetected. In this case, passwords can just be captured programmatically, as users log in. This requires much less effort than brute-forcing strong hash algorithms.
  • The cracker breaks in, steals a copy of the database, and in response the sysadmin plugs the security hole and restores the server from backup quickly.

In the second case, the cracker has a set of usernames, email addresses and hashed passwords, which they may wish to try brute-forcing. There is no advantage to be had if these hashes were created once or a thousand times.

It's worth remembering what we're trying to guard against here. If the security of a website has been breached, there is a knock-on effect for users who have used the same username/password combination at other popular services. A major reason for hashing, and the purpose an attacker has in brute-forcing passwords, is to see if the users can be hacked elsewhere (for example their social media or bank accounts).

This is why we recommend that people should not re-use passwords, and instead that they should use strong passwords stored in a password manager. It is even better if people can use a different username and/or a different email per service. Incidentally, it is surprisingly easy to use an email per service: if you are on GMail with an address of gmail.alias@gmail.com, just do this:

gmail.alias+randomcode@gmail.com

The email should of course be stored in your password manager - if you forget this, you will not be able to use password reminder features, and you will be locked out unless the service is willing to accept some other proof of identity. Despite that, this approach is stronger against the ripple effect of using a service that is breached - a weak password reminder system elsewhere is harder to exploit if users always use different email addresses.

Users with their own domain name can do something similar - set up an email account to "catch all" and then use whatever aliases you like.

Is it an good idea of Using password itself as an salt

A common mistake is to use the same salt in each hash. Either the salt is hard-coded into the program, or is generated randomly once. This is ineffective because if two users have the same password, they'll still have the same hash. An attacker can still use a reverse lookup table attack to run a dictionary attack on every hash at the same time. They just have to apply the salt to each password guess before they hash it. If the salt is hard-coded into a popular product, lookup tables and rainbow tables can be built for that salt, to make it easier to crack hashes generated by the product.

A new random salt must be generated each time a user creates an account or changes their password.


[…] It's easy to get carried away and try to combine different hash functions, hoping that the result will be more secure. In practice, though, there is very little benefit to doing it. All it does is create interoperability problems, and can sometimes even make the hashes less secure. Never try to invent your own crypto, always use a standard that has been designed by experts. Some will argue that using multiple hash functions makes the process of computing the hash slower, so cracking is slower, but there's a better way to make the cracking process slower as we'll see later.

Here are some examples of poor wacky hash functions I've seen suggested in forums on the internet.

md5(sha1(password))
md5(md5(salt) + md5(password))
sha1(sha1(password))
sha1(str_rot13(password + salt))
md5(sha1(md5(md5(password) + sha1(password)) + md5(password)))

Do not use any of these.


Salt should be generated using a Cryptographically Secure Pseudo-Random Number Generator (CSPRNG). CSPRNGs are very different than ordinary pseudo-random number generators, like the "C" language's rand() function. As the name suggests, CSPRNGs are designed to be cryptographically secure, meaning they provide a high level of randomness and are completely unpredictable. We don't want our salts to be predictable, so we must use a CSPRNG. The following table lists some CSPRNGs that exist for some popular programming platforms. (PHP: mcrypt_create_iv, openssl_random_pseudo_bytes)

The salt needs to be unique per-user per-password. Every time a user creates an account or changes their password, the password should be hashed using a new random salt. Never reuse a salt. The salt also needs to be long, so that there are many possible salts. As a rule of thumb, make your salt is at least as long as the hash function's output. The salt should be stored in the user account table alongside the hash.

To Store a Password

  1. Generate a long random salt using a CSPRNG.
  2. Prepend the salt to the password and hash it with a standard cryptographic hash function such as SHA256.
  3. Save both the salt and the hash in the user's database record.

To Validate a Password

  1. Retrieve the user's salt and hash from the database.
  2. Prepend the salt to the given password and hash it using the same hash function.
  3. Compare the hash of the given password with the hash from the database. If they match, the password is correct. Otherwise, the password is incorrect.

At the bottom of this page, there are implementations of salted password hashing in PHP, C#, Java, and Ruby.

In a Web Application, always hash on the server

If you are writing a web application, you might wonder where to hash. Should the password be hashed in the user's browser with JavaScript, or should it be sent to the server "in the clear" and hashed there?

Even if you are hashing the user's passwords in JavaScript, you still have to hash the hashes on the server. Consider a website that hashes users' passwords in the user's browser without hashing the hashes on the server. To authenticate a user, this website will accept a hash from the browser and check if that hash exactly matches the one in the database. This seems more secure than just hashing on the server, since the users' passwords are never sent to the server, but it's not.

The problem is that the client-side hash logically becomes the user's password. All the user needs to do to authenticate is tell the server the hash of their password. If a bad guy got a user's hash they could use it to authenticate to the server, without knowing the user's password! So, if the bad guy somehow steals the database of hashes from this hypothetical website, they'll have immediate access to everyone's accounts without having to guess any passwords.

This isn't to say that you shouldn't hash in the browser, but if you do, you absolutely have to hash on the server too. Hashing in the browser is certainly a good idea, but consider the following points for your implementation:

  • Client-side password hashing is not a substitute for HTTPS (SSL/TLS). If the connection between the browser and the server is insecure, a man-in-the-middle can modify the JavaScript code as it is downloaded to remove the hashing functionality and get the user's password.

  • Some web browsers don't support JavaScript, and some users disable JavaScript in their browser. So for maximum compatibility, your app should detect whether or not the browser supports JavaScript and emulate the client-side hash on the server if it doesn't.

  • You need to salt the client-side hashes too. The obvious solution is to make the client-side script ask the server for the user's salt. Don't do that, because it lets the bad guys check if a username is valid without knowing the password. Since you're hashing and salting (with a good salt) on the server too, it's OK to use the username (or email) concatenated with a site-specific string (e.g. domain name) as the client-side salt.

source: https://crackstation.net/hashing-security.htm

So, to answer your question, bad idea, very bad idea.

Password hashing with true random salt or username salt plus pepper?

Consider the following two methods:

The first method is terrible because it allows attackers who get your hashes to use something like oclHashcat to make, typically, trillions or quadrillions of guesses per month, and the second is horrific because those same attackers can not only make the same, typically, trillions or quadrillions of guesses per month, if they get ahold of the applicationConstantPepper and usernames before they get ahold of your passwords, they can precompute guesses while they work on getting your passwords.

Please read How to securely hash passwords?, in which Thomas Pornin states "For peppering to be really applicable, you need to be in a special setup where there is something more than a PC with disks; you need a HSM." Please read the entire article for context, but the gist of it is:

  • Do use PBKDF2 (also known as RFC2898 and PKCS#5v2), BCrypt, or SCrypt.
  • Do not use a single pass of a hash algorithm, regardless of how good your seasonings are.
  • Do use an 8-16 byte cryptographically random salt.
  • Use as high an iteration count/work factor as your machine can handle at peak load without causing users to complain.
  • For PBKDF2 in particular, do not request or use more output bytes than the native size of the hash function.

    • SHA-1 20 bytes
    • SHA-224 28 bytes
    • SHA-256 32 bytes
    • SHA-384 48 bytes
    • SHA-512 64 bytes
  • If you're on a 64-bit system, consider using PBKDF2-HMAC-SHA-384 or PBKDF2-HMAC-SHA-512, which will reduce the margin of superiority an attacker with 2014-vintage GPU's will have over you.

If you like the pepper concept anyway, please read Password Hashing add salt + pepper or is salt enough?, again, Thomas Porrin's answer in particular.

Salting passwords 101

Salt is combined with the password before hashing. the password and salt clear values are concatenated and the resulting string is hashed. this guarantees that even if two people were to have the same password you would have different resulting hashes. (also makes attacks known as dictionary attacks using rainbow tables much more difficult).

The salt is then stored in original/clear format along with the hash result. Then later, when you want to verify the password you would do the original process again. Combine the salt from the record with the password the user provided, hash the result, compare the hash.

You probably already know this. but it's important to remember. the salt must be generated randomly each time. It must be different for each protected hash. Often times the RNG is used to generate the salt.

So..for example:

user-password: "mypassword"

random salt: "abcdefg12345"

resulting-cleartext: "mypassword:abcdefg12345" (how you combine them is up to you. as long as you use the same combination format every time).

hash the resulting cleartext: "somestandardlengthhashbasedonalgorithm"

In your database now you would store the hash and salt used. I've seen it two ways:

method 1:

field1 - salt = "abcdefg12345"

field2 - password_hash = "somestandardlengthhashbasedonalgorithm"

method 2:

field1 - password_hash = "abcdefg12345:somestandardlengthhashbasedonalgorithm"

In either case you have to load the salt and password hash out of your database and redo the hash for comparison

Why to store salt along with hashed password in database

What if we don't salt?

You already understand at this point that if you use Password1 on its own (without a salt) then every time you hash it, you will get the exact same result. Now, let's pretend you have 1000 users and of those 1000, 25 of them use the same password. Those 25 hashes are going to be exactly the same. Once an attacker gains access to your database and finds the hash 70ccd9007338d6d81dd3b6271621b9cf9a97ea00 translates to Password1, they will have gained access to 25 people's accounts in no time at all. This means a rainbow table attack will allow him to access more accounts, faster.

What if we do salt?

By appending a salt to the value of Password1 you are going to dramatically change the hash. Each user should have their own salt. This means that even if you have all 1000 of your users using Password1, all 1000 hashes will be completely different. In real real world, this means that the 25 of your 1000 users who have the same exact password will all have different hashes. However, it also means an attacker will have to run an attack on one password at a time, rather than just rainbow tabling the hashes and hoping for the best.

But why do we store the salt?

Without the salt, you won't be able to recreate the hash when the user enters their password - meaning the user can never log in again and access their account. By storing the password, you can allow the user to enter their password and then you run a lookup on their account, append the salt to their input, and hash the entire thing; if it matches the hash stored in the database you've got the right password! If you never store this salt, you can never recreate the hash!

I hope this explains a little better, and as always if you have any comments feel free to ask

Do I need a random salt once per password or only once per database?

A new salt should be randomly generated for each user and each time they change their password as a minimum. Don't just rely on a site wide salt for example, as that defeats the point of using a salt in the first place.

Using a unique salt for each user is so that if two users have the same password they won't get the same resultant hash. It also means a brute force attack would need to be mounted against each user individually rather then being able to pre-compute a rainbow table for the site.

You then store the result of hashing the salt and password in the database hash(salt + password), along with the salt for each user. You can store these in separate columns, or all in one column (separated by some character not used in the hashes, so ; for example). As long as you can retrieve both you'll be fine.

However, if your database is compromised, either due to someone gaining local access or via SQL injection attacks, then both the salt and final hash will be available, which means a brute force attack on the users' passwords would be trivial. To combat this, as suggested by The Rook you can also use a sitewide secret key stored in a file locally as another input of your hashing method so that an attacker would also need to know this to mount an effective attack. Which means your DB would have to be compromised AND the attacker would need access to local files. So using hash(hash(salt + secret) + password), etc.

While in most algorithms you aim to make things as fast as possible, for password hashing you want to slow it down, this is called Key Strengthening (or sometimes Key Stretching). If it takes 0.00001 seconds for your hash function to return, someone can try brute forcing 100,000 passwords a second until they find a match. If it takes 1 second for your hash function to spit out the result, it's not a big deal as far as someone logging into your application is concerned, but for cracking the password it's a bigger deal since each attempt will now take 1 second to get a result, meaning it would take 100,000 times as long to test each brute forced password than it would using your original hash function.

To make your hash function slower, you just need to run it multiple times. For example, you could do new_hash = salt + password + previous_hash 100,000 times. You may need to adjust the number of iterations to a higher value if it's too quick. If you want to be able to change the value later, make sure to store the number of iterations with the user record so that you don't affect any passwords previous stored.

Your user record should now have a field formatted something like this "$<algorithm>$<iterations>$<salt>$<hash>" (or as separate fields if you want).

When the user enters their password you can retrieve the salt and number-of-iterations from the DB and the sitewide secret from a local file and validate that when you run the same number of iterations with the salt and password, the resulting hash matches what you have stored.

If the user changes their password, then you should generate a new salt.

The hashing method you use doesn't matter (but the hashing algorithm does*). Above I suggested hash(hash(salt + secret) + password) but equally it could be hash(hash(salt) + hash(secret) + hash(password)). The method you use doesn't change the effectiveness of your password storage, one is not really any more secure than the other. Relying on the design of how you hash the password and salt together to provide security is called security through obscurity and should be avoided.

*You should not use MD5 or SHA-1 as these are considered insecure. Use the SHA-2 family instead (SHA256, SHA512, etc). (Ref)



Related Topics



Leave a reply



Submit