2

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 :)

jww
  • 83,594
  • 69
  • 338
  • 732
ACs
  • 1,105
  • 16
  • 31
  • 1
    Have you read [The definitive guide to form based website authentication](http://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication)? – Oleg Estekhin Apr 30 '14 at 10:46
  • 2
    Question 4: use `password_hash` or its compatibility library. It's an easy to use wrapper over bcrypt. – CodesInChaos Apr 30 '14 at 14:00
  • Also see Openwall's [Portable PHP password hashing framework](http://www.openwall.com/phpass/) (PHPass). Its hardened against a number of common attacks on user passwords. – jww Oct 11 '14 at 23:42

2 Answers2

2

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,kHash(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 .

Community
  • 1
  • 1
Perseids
  • 10,688
  • 5
  • 32
  • 62
0

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.

martinstoeckli
  • 21,405
  • 4
  • 52
  • 78
  • As ACs is confused already I'll be nit-picky about the terms. By definition *encryption* is always two-way, there is no such thing as "one-way encryption". That would be called *one-way hashing* (or *one-way functions* in general). It is pretty unfortunate that so many sources talk about "password encryption" when they really want to say "password hashing". – Perseids Apr 30 '14 at 20:04
  • @Perseids - That's actually what i wrote, i thought it would make things more clear if it is mentioned explicitely. Anyway i tried to reword it slightly. – martinstoeckli Apr 30 '14 at 20:09
  • Are you interested in some feedback regarding the tutorial? – Perseids Apr 30 '14 at 20:17
  • @Perseids - Yes of course, i worked a very long period on this tutorial. Keep in mind that english is not my native language, but this must not affect correctness of the content. – martinstoeckli Apr 30 '14 at 20:20
  • @Perseids - Thank you very much for your feedback, its really appreciated! You've got mail too :-) – martinstoeckli May 01 '14 at 07:41