Im creating a PHP based CMS (using MVC architecture). I'd like to hash the user passwords stored in the DB. I have read many artices and tutorials about this topic, but I've faced opposing opinons/points of view and suggestions. Im a bit confused. Im looking for the best way to implement password hashing. These are the concepts/methods I've met:
First of all many people mix up the 1-way hashing and the 2-way encryption. If i'm not mistaken the 2-way encryption is the thing about the assymetric encryption with public-private keypairs, And it is for securing the data and make it only readably by the ones who know the other key (the secret key). So this is what we don't care about now.
PHP provides many functions to making hashes, some of them directly uses a hashing alogrithm on the given data (md5(), sha1(), sha256(), ripemd160() etc.) some of them accepts the given data and a supported algorithm and generates the hash (hash(), hash_init(), hash_hmac() etc.)
What is the difference between the loads of hashing/crypting methods? (hash_pbkdf2(), crypt(), bcrpyt, password_hash() and the others mentioed above)
as I learned it is a good practice to use salts in your hash, but it is a bad idea to hash multiple times (even so many tells it is good). Some functions use salt others use key...
Question 1:
Could someone clarify what is the difference between eg.: md5('myPassword'); and hash('md5', 'myPassword'); (I know md5 is an easy to hack method and is not recommended to use to store passwords)
Question2:
And what is the difference between the key and the salt? So what is the difference between hash_hmac('sha1', 'myPassword', 'HaCK_MeIF_youCAN'); and sha1('myPassword'.'HaCK_MeIF_youCAN');?
(notice that hash_hamc calls its 3rd argument 'key')
Question3:
Is multiple hashing really a bad practice?
Like:
hash = sha512(password)
for i in range(10000):
hash = sha512(hash) + salt
return hash
Question4:
What should be the best method to hash my passwords?
Since this is an important and sensitive issue and I think others not familiar with the topic like me would like to make this hash thing clear and would like to get accurate and reliable answers once and for all, I ask you to answer just in case you are an IT security expert or you have any certification or degree in this topic! (For self-proclaimed security experts who acquired their knowledge on the internet: The fact you have done hundreds of systems/websites with hashed passwords doesn't mean that they are secure!)
And one last request: simple (beginner) webprogrammers aren't aliens nor theoretical mathematicians. So please try to explain in some human-like english :)
There are a lot of questions about password hashing on Stack Exchange already, so this is basically a duplicate question, but as you don't know what to trust I'll give you some pointers.
Re: Question 1: Probably they are just different interfaces for the same code. (I haven't checked though. If you want to be sure put the same input in both and compare the output. Or just look up the documentation or in the source code.)
Re: Question 2: A key is a private piece information that you normally should never publish (except for public keys in asymmetric cryptography). Usually there are no keys in password hashing. A salt is a piece of public information that is random and is meant differentiate your password hashing from every other precomputed hash table in the world. It is the main defense against rainbow tables.
HMAC (basically m,k⟼Hash(k||Hash(k||m)) for the concatenation operation ||) was designed to be a so called message authentication code. It is (ab)used for many other purposes though, because of its versatile design if instantiated with a good cryptographic hash function. In this case using the salt as key and the password as message in HMAC is really not that different from Hash(password||salt).
Re: Question 3: No, it is a good practice. The main attack scenario of password storage is that your database is compromised (and often all password data is published if your are significant enough that people will care). Most non technical folk (and apparently even some with IT background) often reuse their passwords (which is a bad practice even if everyone would get their password hashing strait). Thus with your database breach a lot of accounts of a lot people suddenly have known login information if you save the passwords as plaintext. To prevent this you want to use a oneway function on the passwords. Unfortunately passwords have very few entropy most of the time (because nobody likes to remember cryptographically secure passwords) and thus if you use a fast hashing function you can try out every likely password and compare the hash against the one in the database. As extreme example, lets assume I only use the password cat or dog and you have the sha1 hash of my password: 8f6abfbac8c81b55f9005f7ec09e32d29e40eb40 generated by echo $password | sha1sum. Exercise for the reader: which password have used?
To alleviate this problem you want to use a slow hashing function so that trying out every likely password takes a lot of time. One way to slow down the hashing is to iterate the hashing a few thousand (or even few hundred thousand) times. There are other slow hashing concepts like bcrypt, though, that do not just iterate hashing.
Re: Question 4: An in depth discussion can be found on security.stackexchange.com: https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords . The tl,dr version is CodeInChaos's comment: Just use password_hash, it is mostly fool proof. A resource for the advance topic of pepper in addition to salt can be found here: https://security.stackexchange.com/a/3289/10727 .
I will try to answer some of your questions, but first a word about encryption. The problem of encryption is that it is two-way, the password can be retrieved if you know the key. Storing only a hash (one-way) will protect passwords better, because the passwords cannot be retrieved even if all code (including a key) is known.
Question 1 & 2:
It is important that you avoid all fast hashing algorithms, this includes MD5, SHA*. Because they are so fast, they can be brute-forced too easily. It is e.g. possible to calculate about 8 Giga MD5 hashes per second with common hardware.
Question 2:
A salt should be randomly generated for each password, but is not secret and can be stored plaintext with the password in the database. A key (sometimes called pepper) should be kept secret and is not stored in the database.
Question 3:
Multiple hashing is a good thing, but only if done correctly. Appropriate algorithms like BCrypt and PBKDF2 do it in a safe way, and they have a cost factor that determines the number of iterations. This cost factor can be adapted for future and faster hardware.
Question 4:
At the moment the best you can do is to use the PHP function password_hash() to create a BCrypt hash. There also exists a compatibility pack for earlier versions. I wrote a tutorial about safely storing passwords, where i tried to answer this questions a bit more indepth and in a hopefully understandable form, so you mave have a look at it.
Related
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
We need to store passwords (real information stored is some very specific business information but can be compared to passwords to simplify the question). The passwords should be hashed/encrypted.
We do not want to be able to read the passwords but to be able to know which users have the same.
What if we crypt() with a CRYPT_BLOWFISH hash using always the same salt?
How can we hash/encrypt the passwords and ensure that if the database is compromised, the attacker will not be able to read or decrypt them?
With passwords you are always looking for hash, you don't want or need to decrypt them. Thus what you are looking for is a strong hashing algorithm, blowfish or SHA512 I would suggest. As for your question of different user password comparison, well that would significantly reduce the overall security of the system.
You want to include a random salt with each password to make it impossible to precalculate the hashes, so even the same password would have a different hash for each user, otherwise an attacker might find out which of the users use the same passwords and use it to their advantage. Using the same salt for every password defeats its purpose and using none allows for usage of rainbow tables, so you will have to sacrifice that particular feature if you want a secure design of the application.
Edit: sorry deleted the comment and posted it as answer
I suppose if you are looking for a compromise you would be looking at a lot of hashing iterations, perhaps with a large random salt common to all passwords. That should ensure that there aren't any already available precalculated tables to use for cracking the passwords and increase the cracking time. Algorithm chaining might also be an option, but you might run into a performance issue if there are a lot of users. Essentially if you still want to be able to compare user passwords, make it time consuming to calculate the hash, which should radically increase the cracking time. Again to stress, this would be a compromise and definitely is not the most efficient and secure way to go around this issue.
It entirely depends on what your business information is. You already have seen, that hashing would be preferable over encryption, because it cannot be decrypted (otherwise you would have asked differently).
The problem why you cannot hash the information like a password, is that the salt would be unique and the hash function would therefore result in uncomparable hashes-values. If we could do without a salt, we could use a hash function for your purpose.
Salting is done, because passwords are normally short textes (people have to remember them). By checking dictionaries or rainbow-tables we could find the original password very fast, but there are no existing rainbow-tables for salt+password textes. To say it differently, very strong passwords with a certain length would not need salting to be safe. If your business information has enough unique information (entropy), you could do the hashing without a salt and use BCrypt or PBKDF2.
You would need a salt and bytes array to store sensitive information. You could then encrypt the pair with a master key stored somewhere else, safely. With 2 phase encryption you can roll your keys as often as need for security purposes. Your application would need to be able to combine the pieces to compare data.
With passwords I and many others on SO and other websites highly recommend Bcrypt; Bcrypt is a computing intensive hashing algorithm, designed to be slow and expensive to brute-force.
You can read more about Bcrypt on an answer here:
How do you use bcrypt for hashing passwords in PHP?
As for comparing the values, you can't with Bcrypt, but you can check if the value is correct.
So recently I have been doing tons of research on how to secure passwords. I believe I understand the basics of it. As such I am attempting to write my own function to secure a password in php.
But I am somewhat confused when it comes to salting a password. We create a random unique salt and append it to a password and then hash it, and finally store the unhashed salt and hashed password/salt combination together in the database. This increases the search space of the hacker if he obtains access to the database and our hashed passwords.
So this seems like complete overkill of security, but everywhere I see the salt is always appended to the front or back of the password anyways. So looking at a SINGLE user's password this unique salt doesn't affect the search space does it? Although since each user has a unique salt the overall search space of EVERY user is dramatically increased.
Wouldn't it be more secure to create an algorithm that inserts the salt to a predictable, semi-random place in the password such as the length of the username/2? For example here is the steps of my proposed securing function:
Create a random salt
take username length %(mod) password length
insert the salt at the spot determined
hash
Example run:
random salt = 12345
len("imauserwithalongname") % len("mypass") = 2
valueToHash = my12345pass
Now our cracker has no idea where to put the salt without seeing our php/source, which (correct me if I am wrong) is much harder to gain access to than the database.
Also I know security should depend on the security of the key not secrecy of the algorithm, however I see nothing wrong with adding layers based on it, as long as the entire system does not depend on secrecy of the algorithm.
EDIT: Would doing this dramatically increase the search space of a cracker?
And what if we placed the salt in a place that depended on the length of the password, would that not destroy the purpose of using dictionary attacks, even on a per user basis?
Inserting the salt in a different spot doesn't increase the search space. If you are using a random salt for each user, a hacker does not know what each salt is per user anyway. The knowledge of its position in the unhashed string doesn't matter.
Use bcrypt or PBKDF2. Both algorithms enforce a salt and number of cycles. If you're patient enough, PHP 5.5 will just let you do password_hash($password).
As such I am attempting to write my own function to secure a password
in php.
Woah woah, hold it right there.
There's a saying passed down from cryptographers to us mere mortals which has held true for many many years. The saying goes like this:
Do not invent your own crypto.
Say it out loud, then say it again.
I know you're only trying to secure your passwords, but I had to get that out of the way. There are lots and lots of tried and tested methods to do what you want to achieve.
I appreciate you've done some research, but the internet is full of terrible terrible information, so I'm going to point you towards some useful articles.
Check out ircmaxell's security related
blogs.
A nice short list.
Here's some keywords to help you.
Bcrypt
Scrypt (someone please unstrike this when PHP supports it)
Again a very short list.
To address your specific concern. Salts are not needed to be kept private, as you say they are designed to stop attackers precomputing tables of valid password/hash combinations. However if you use a weak hashing algorithm they lose their value very quickly.
Security through obscurity is not as great as it seems. If a hacker gains access to your DB, the odds are quite high that they will also gain access to your filesystem. If they gain access to your source your custom method of storing passwords is a moot point.
In summary, custom algorithm + weak hash = insecure.
Instead you want to use tried and tested key derivation functions / key strengthening algorithms.
These are designed to make the computer work really hard to generate the hash, and makes it very difficult for an attacker to brute force a password.
Bcrypt stores the salt next to the password, and is proven to be very secure. Secure enough in fact that it is currently the recommended way to hash passwords by security experts.
In PHP 5.5 a simple password hashing API has been introduced based on Bcrypt, and for versions under 5.5 there is a password hashing compatibility library that does exactly the same thing.
That should be enough for you.
I personally think you're overdoing it. The most efficient way to salt a hash would be to have a dynamic, record-specif one AND a static one stored in a read-only file on the system. This is a very efficient yet secure way of salting hashes.
I think you misunderstood the purpose of the salt. The salt does not increase the search space for an attacker, after all it is stored plaintext with the hash-value. The purpose of a salt is, that an attacker cannot build one single rainbowtable, and then retrieve all stored passwords.
If you would append the same salt to every password, then the attacker cannot simply use an existing precalculated rainbow-table from the internet, he has to build a new rainbow-table for exactly this salt (existing rainbow-tables will contain passwords like "horse", but not passwords like horse8ze*w398dhek3+qmxno0). Unfortunately this single rainbow-table can then be used to get all passwords.
So we use a unique salt for every password. An attacker would have to build a separate rainbow-table for each password now, but why should he continue with building the table, when he already found a match (?), he cannot reuse the table later for other passwords. In other words, brute-force is faster than building a rainbow-table, so we made rainbow-tables useless.
So the salt should be unique for each password and if possible it should be unpredictable. Those criterias are difficult to fulfill with a deterministic computer, the best you can do is, to use the random source of the operating system to build the salts. Good hash algorithms for passwords like BCrypt and PBKDF2 repeat the hashing to become slow, and combine password and original salt in each iteration. It is not just a concatenation of password + salt.
Your idea about putting the salt somewhere secret does add a secret (where is the salt?), that will work as long as the attacker doesnt know your code. Getting the database (SQL-injection) is indeed easier than gaining access to the code, but the same goal can be achieved much easier with a pepper.
I tried to sum up this in a tutorial, maybe you want to have a look at it.
I'm the developer of a new website built in PHP and I'm wondering what exactly is the best
thing to use for hashing. I've looked at md5 and sha1 but is there anything more secure.
I'm sorry if this is a nooby question but I'm new to PHP Security and I'm trying to make my
site as secure as possible. Also what is a salt?
Thanks,
Waseem
First off md5 and sha1 have been proven to be vunrable to collision attacks and can be rainbow
tabled easily (When they see if you hash is the same in their database of common passwords).
There are currently two things that are secure enough for passwords, that you can use.
The first being sha512. sha512 is a sub-version of SHA2. SHA2 has not yet been proven to be
vunrable to collision attacks and sha512 will generate a 512 bit hash. Here is an example of
how to use sha512:
<?php
hash('sha512',$password);
The other option is called bcrypt. bcrypt is famous for its secure hashes. Its
probably the most secure one out there and most customizable one too.
Before you want to start using bcrypt you need to check if your sever has it enabled, Enter
this code:
<?php
if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
echo "CRYPT_BLOWFISH is enabled!";
}else {
echo "CRYPT_BLOWFISH is not available";
}
If it returns that it is enabled then the next step is easy, All you need to do to bcrypt a
password is (Note for more customizability you need to see this How do you use bcrypt for hashing passwords in PHP?):
crypt($password, $salt);
Now to answer your second question. A salt is usally a random string that you add at the end of
all you passwords when you hash them. Using a salt means if some one gets your database
they can not check the hashes for common passwords. Checking the database is called using a rainbow table. You should always use a salt when hashing!!
Here are my proofs for the SHA1 and MD5 collision attack vulnerabilities:
http://www.schneier.com/blog/archives/2012/10/when_will_we_se.html, http://eprint.iacr.org/2010/413.pdf, http://people.csail.mit.edu/yiqun/SHA1AttackProceedingVersion.pdf, http://conf.isi.qut.edu.au/auscert/proceedings/2006/gauravaram06collision.pdf and Understanding sha-1 collision weakness
The whole purpose of the salt is to slow down an attacker from comparing a list of pre-generated hashes against the target hash.
Instead of needing to pre-compute one "hashed" value for each plaintext password, an attacker needs to precompute 16384 "hashed" values for each plaintext password (2^7 * 2^7).
That kinda pales today but was pretty big when the crypt function was first developed - the computational power to pre-compute that many passwords times the number of plaintext password you suspect (dictionary) was pretty high.
Not so much today which is why we have things like shadow passwords, other core password functions besides crypt and every sysad wanting you to pick a password that would not show up in a dictionary.
If the hashes you want to generate are for passwords this is a well accepted method of implementing it.
http://www.openwall.com/phpass/
If you're planning to do this for passwords, then do not use MD5 or SHA1. They are known to be weak and insecure, even with salt.
If you're using them for other purposes (eg providing a hash of a file to confirm its authenticity, or a random hash database column to provide a pseudo-random sort order) then they are fine (up to a point), but not for passwords or anything else that you would consider needing to be kept secure.
The current best-practice algorithm for password hasing is BCrypt, with suitable salting.
And the best way to implement BCrypt password hashing in PHP is to use PHP's new password API. This API will be featured as a set of built-in functions in the next version of PHP, v5.5, due for release in the next few months. The good news is that they have also released a backward-compatibility version for users of current versions of PHP (5.3 and 5.4), so even though PHP 5.5 isn't released yet, you can start using the new API immediately.
You can download the compatibility library from here: https://github.com/ircmaxell/password_compat
Also: You asked what "salt" is. Since I've mentioned it a couple of times in this answer, I should address that part of the question too.
Salt is basically an additional string added to the password when hashing it, in order to make it harder to crack.
For example, an attacker may know in advance what the hashed value is for a given password string, or even a whole lot of given password strings. If he can get hold of your hashed data and you haven't used a salt, then he can just compare your hashes against his list of known passwords, and if any of your users are using an easy to guess password, they'll be cracked in seconds, regardless of what hashing method was used.
However, if you've added a secret extra string to the password when you hash it, then the hashed value won't match the standard hash for the original password, thus making it harder for the attacker to find the value.
The good news is that if you're using the API I mentioned above, then you don't need to worry too much about the details of this, as the API handles the salting for you.
Hope that helps.
I am seeking advice on how to securely store passwords in MySQL using PHP.
Overlooking the limitations of PHP itself, I want to know more about salting, hashing, and encrypting these bad boys.
Obviously people will continue to use weak passwords unless forced to do otherwise, but it's how I am storing them that is important to me. My user's passwords are far more important to me than the database itself, and as such I want to keep them in such a way that it will be painstaking and monotonous for any script kiddie trying reverse. Obviously with due diligence just about anything can be defeated, but I wouldn't mind making this particularly bothersome.
There are two scenarios we are looking at.
The kiddie has a complete copy of the database.
The kiddie has a complete copy of the PHP used to craft the password, and the database.
Any and all advice on this topic is graciously appreciated.
Use bcrypt. If someone has the user table of your database, then they can use brute force/rainbow tables/etc to their heart's content. Even with salt, if you're using MD5 or some other fast-hashing algorithm (which aren't designed to solve this problem, by the way); it's just a matter of time before it can be cracked.
Any well-known and widely-supported hashing algorithm is going to have this same basic "flaw" (if you can call it that; it's really by definition). The difference is that bcrypt is slow as molasses when performing the hashing operation, rendering a brute force attack much less effective.
For an absolutely great discussion on the merits of bcrypt, the dangers of other approaches, and the difficulty of password security in general, read this thread. It has lots of comments by many people that are much more knowledgeable about this sort of thing than I am, and it should hopefully help you understand more of the issues at stake.
Assuming you're using username and password as authentication tokens you can safely store the following to ensure the data can't be compromised.
Username (in plaintext)
Salt (random string)
Salted Hash (sha1(username + salt + password))
Using the scheme, an attacker cannot use rainbow tables against you and the passwords are not recoverable by any (reasonable) means. (That is, as long as your attacker isn't the government)
Even though the attacker has the salt and hash pairs it's not possible to use rainbow tables because all the possible hashes will need to be computed anyway, using the salt that they've been given, so it's a brand new brute force attack for each user.
Even with the source code and attacker won't be able to get hold of the passwords because the strength/security is in the hashing algorithm, not your code.
Combine this with using bcrypt as per Donut's answer and you're really quite safe. That is:
Username (in plaintext)
Salt (random string)
Salted Hash (bcrypt(username + salt + password))
Taking advice from here, for added fun you can dynamically change your salt as well. For example, use different salts for usernames of different length, use the user's registration date as the salt. This makes it that even if someone DOES get to your database, they can't just re-generate the hash, they have to calculate a hash table for each salt that you used.
If your users are over the internet, OpenId would be one of your best options. http://openid.net/
If your users are on your network, can you do Integrated Security?
In other words.. do not store their passwords.
Usually "salted" passwords (like with bcrypt) mean that not the password itself is stored, but only something like
salt
hash(salt with password appended)
Now if the kiddie has your database (and of course, the code - there is no point in keeping the code secret), he/she can only guess passwords, calculate the salted hash, and compare. If the hash function is expensive (like bcrypt is), than guessing is expensive too.
It's simple
store(sha256("somesalt" + password));
And nobody will be able to reverse it :)
See also: https://stackoverflow.com/questions/3897434/password-security-sha1-sha256-or-sha512
I have a user table in my mysql database that has a password column. Currently, I use the MD5 algorithm to hash the users' password for storage in the database. Now I like to think that I am a security conscience person. I noticed while reading the MySQL docs that they don't recommend MD5 or the SHA/SHA1 hashing methods, but don't offer an alternative.
What would be the best way to hash my passwords in MySQL? A function that is natively supported in both PHP and MySQL would be ideal and necessary with my current implementation.
Thanks!
It's not necessarily that you shouldn't use MD5, as much it's that you shouldn't use just MD5, as this leaves you vulnerable to rainbow-table attacks (a rainbow table is a table of precomputed hash values - if your password is even remotely common or simple, the attacker needs merely to look up the hash and he knows your plaintext password.)
At the very least you should add a salt to every password so that any existing rainbow table is useless, forcing the attacker to generate an entire new rainbow table just for your database of passwords.
Better still is to use a different salt for every password in your database, say the username it's associated with, so that an attacker can't even generate a rainbow table for your whole database and has to crack each entry separately.
MD5 is also a very fast algorithm. Speed is the enemy when it comes to cracking - the longer it takes to generate a hash, the longer it takes for each attempt a hacker makes. Something simple like hashing the plaintext 100 times with a new additional salt each time would be barely perceptible (if at all) to a user logging in to your site, but it would increase the time it takes to brute-force a password by the same 100 times.
Far, far more detail here: http://www.codinghorror.com/blog/archives/000953.html
MD5 is considered to be weak by today's standards. It would still take some work to crack a hash made with MD5, but it's several times easier than guessing the password by brute-force. Ideally, cracking a hash should not be easier than brute-force.
SHA1 is also considered easier to crack than guessing the password by brute-force.
I actually contributed a patch to MySQL to surface the SHA224, SHA256, SHA384, and SHA512 functions from OpenSSL. These are recommended by NIST for password hashing (actually SHA256 and higher).
My patch was finished by MySQL engineers, and is included in MySQL 6.0.5 and later, if I recall.
If you use an earlier version of MySQL (and who doesn't), then you can probably use an implementation of strong hashing functions in your host language. PHP has the hash() function for example. You can do the hashing in your application and save the resulting message string to the database.
Don't forget to do salting, too!
This question is 7 years old. In that time we have progressed in computing to where MD5 and SHA1 are now easily broken by modern computers. These should be avoided now.
With PHP 5.5 came the introduction of password_hash, which uses the far more secure bcrypt algorithm. While MySQL can encrypt/decrypt bcrypt, it's a terrible solution because you're not only adding a potentially large computation load to your database layer, but the unhashed password could be stored in your logs
Under no circumstances should a plain text password hit MySQL, even if at the query level. Otherwise you risk writing the passwords to log (query log, general log, slow query log, etc). Which is horrific. So no, don't even bother...
MD5 and SHA-1 probably aren't recommended anymore due to know attacks. But, they're still generally sufficient for most use cases.
If you're looking for more options, just use PHP's hash functions -- you've got plenty of options there.
I am using a combination. For example SHA1(MD5()) is working fine.