views:

4479

answers:

5

I'm making a php login, and I'm trying to decide whether to use SHA1 or Md5, or SHA256 which I read about in another stackoverflow article. Are any of them more secure than others? For SHA1/256, do I still use a salt?

Also, is this a secure way to store the password as a hash in mysql?

function createSalt()
{
    $string = md5(uniqid(rand(), true));
    return substr($string, 0, 3);
}

$salt = createSalt();

$hash = sha1($salt . $hash);
+6  A: 

Neither. If at all possible, you should use bcrypt. The hashes you mention are all optimized for speed and as such they are easily cracked. If you must use them, be sure to use a long salt and re-hash multiple times.

Johannes Gorset
can you elaborate? what is bcrypt? i don't see any good online examples of it...
hatorade
also, i'm very new at this: are sha1, sha256, and md5 all the 'hashes' you refer to?
hatorade
Yes. I'm referring to SHA1, SHA256 and MD5 and a series of other hashes that are optimized for speed. You don't want to use a hash optimized for speed to secure a password.There are many good articles discussing why, and I like this one in particular:http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
Johannes Gorset
is there a bcrypt function in php...? (that might be a totally newb question)
hatorade
It's included in the "crypt" function since PHP 5.3. If you have an earlier version, I'd look into the "phpass" framework for the next best thing.
Johannes Gorset
so if i were to implement crypt in PHP, I would just call crypt on my password i want for the admin, store that in a mysql DB, and then just run crypt() on the password entered on the login page and make sure they are equal, right?
hatorade
Yes, that's right.
Johannes Gorset
so, if my password is 'zebra': crypt(zebra) -> store this in DB. At login page, user types in 'zebra', and i just check 'crypt('zebra') = stored_hash_for_this_user
hatorade
in other words, i don't put a salt anywhere, it just adds one for me if i use that syntax?
hatorade
FRKT is dangerously oversimplifying about the "ease" of cracking the MD5/SHA* hashes compared with bcrypt. However, bcrypt sounds like the right tool for the job, whereas the programmer has to understand about salting and iteration counts with the MD5/SHA*.
GregS
@GregS: You're right that MD5/SHA* passwords that have been hashed multiple times with an unique salt become harder to crack (in fact I'm inclined to agree with you that it would no longer be "easy"), but the fact remains that bcrypt is the better option simply because it's slow as hell and MD5/SHA* isn't.
Johannes Gorset
Tell me an instance where SHA256 has been hacked?
Stanislav Palatnik
@Stanislav Palatnik I don't know that SHA256 has, but that's besides the point; bcrypt is a better choice.
Johannes Gorset
@FRKT : unless you are developing mission critical applications, you can use SHA512(I'll give in and say SHA256 will not give me peace of mind with sensitive applications). SHA512 will not be cracked by the time SHA3 comes out. Then you can switch to SHA3 hashing.
Stanislav Palatnik
@Stanislav Palatnik SHA512 is a good alternative. Don't get me wrong; I'm not saying a stretched and salted SHA512 hash is insecure. It's secure. Even so, the fact remains that bcrypt is *more* secure, and so I see no reason not to use it.
Johannes Gorset
+3  A: 

Use SHA256. It is not perfect, as SHA512 would be ideal, but out of the options, its the definite choice. As per any hashing technology, be sure to salt the hash for added security.

As an added note, FRKT, please show me where someone can easily crack a salted SHA256 hash? I am truly very interested to see this. SHA1 has been cracked, MD5 the same. SHA256 to my knowledge has still not been broken.


Edit on Salting:

Use a random number, or random byte stream etc. You can use the unique field of the record in your database as the salt too, this way the salt is different per user.

Kyle Rozendo
But their optimized for speed, meaning that they enable brute-force hacking.
arbales
Fact remains, this is to secure a password. By using a hash with a salt, then add a 3 attempt limit on the website, you substantially slow down the hackers attempts (even brute forcers). Using any pure encryption, you now have another problem - securing the key. If the key is found, your entire database is compromised (if no salt is added). Hashes however, you will never get the original password out of the system, and thats how it should be.
Kyle Rozendo
As noted, the problem with the MD and SHA-series is that they are optimized for speed. It is inevietable that hashes of this nature become increasingly insecure as computing evolves.
Johannes Gorset
*Anything* becomes increasingly bad/insecure/etc as computing evolves. By the time SHA512 etc. are hacked, there will be more secure algorithms available. This is the nature of computing in any case.
Kyle Rozendo
what is a good way to make a salt in php? have example code? i imagine i shouldn't just pick something like 'giraffe'
hatorade
@Kyle Rozendo Brute-force attacks are not exclusive to the login system of your website. The real risk lies in a compromised database. It does not take long to generate dictionaries (complete with salts) for MD/SHA hashes.
Johannes Gorset
@Kyle Rozendo You are incorrect. Bcrypt does not become insecure as computing evolves, which is exactly why you should use it.
Johannes Gorset
No no. Use a random number, or random byte stream etc. You can use the unique field of the record in your database as the salt too, this way the salt is different per user.
Kyle Rozendo
@FRKT - If your database is reached, you are screwed in any case. Before you secure anything, your entire internal network should be bullet proof.
Kyle Rozendo
so do i use rand() or something to make a random number?
hatorade
Use the unique identifier of the field in the database.
Kyle Rozendo
@Kyle Rozendo: "Bullet proof"? You should know there's no such thing in this industry. Either way, passwords encrypted with bcrypt remain little more than a hash even if your database is compromised. There's no reason to use MD/SHA if bcrypt is available.
Johannes Gorset
Sure, but you are absolutely missing the point. If they have access to the database, they don't actually need the password anymore - it is irrelevant. You will be finished.
Kyle Rozendo
i only have 1 person in my DB (1 admin). so the unique ID would be 1. that's not a very good salt, right? maybe i'm extremely ignorant on this, but i thought that the longer the salt was, and the more random, the better?
hatorade
@Kyle Rozendo: It is absolutely relevant, seeing that most users use the same password for multiple services.
Johannes Gorset
@hatorade: The longer the salt, the more secure the password.
Johannes Gorset
so how do i make a good, long, random salt?? rand()?
hatorade
@FRKT - Firstly, the hashed password will not ever be able to be recovered if hashed with a salt (I use GUID salts). @hatorade - If its still early days in the design, try use a GUID field as your ID. Not certain how to do it using MySQL though, but in MSSQL it provides some very nice benefits.
Kyle Rozendo
@hatorade: Any random and long value will do.
Johannes Gorset
@Kyle Rozendo: You are wrong in your perception that the MD/SHA series of hashes are secure, salted or not. There are many great articles that describe their shortcomings more in detail. Perhaps http://codahale.com/how-to-safely-store-a-password/ will convince you. You seem determined to learn the hard way, though.
Johannes Gorset
I am not fighting you on the merits of bcrypt, or the pitfalls of hashes. I am simply saying that an assumption such as "are easily cracked" is completely silly. Every single form of security can and will be broken. The one thing I definitely give you is that you are definitely making life hard enough for a hacker to go elsewhere.
Kyle Rozendo
@FRKT: PKCS5 has been around for about 15 years now and recommends salting and iteration counts. Blowfish has also been optimized for speed, even though bcrypt deoptimizes it. Essentially, bcrypt is about the same as salting/iterating the MD5/SHA* hashes.
GregS
A: 

Sorry, but is it possible to crack md5 hash? A thought, that it is pretty strong.

Eugene
It is not possible when you don't know anything about the original string. It is possible when it is a password - people use weak passwords, you just have to take a dictionary, and try its words in various combination with each other and numbers, and see if one hashes to the same value. The cryptographic properties of the hash function do not matter for such an attack - the only thing that counts is how fast `md5('some_password_guess)' can be calculated; the faster it is, the more passwords the attacker can try in the same time. And md5 is very fast. bcrypt OTOH was designed to be slow.
Tgr
But if I use for example function which was brought up here createSalt() and make it even harder, then it should be ok, doesn't it?
Eugene
Whoever wrote createSalt() didn't have much idea what he is doing. He is using the high bits of the random number and the uniqid call has no effect; more importantly, the salt is way too short. Most importantly though, salting does not protect you against a bruteforce or dictionary attack; that is not its purpose. Never mind how hard it is to calculate a hash function backwards, the attacker only has to calculate forwards, and calculating a salted md5 hash is fast. You need to have a hash function that is slow.
Tgr
+1  A: 

As FRKT pointed out, the post by Thomas Ptacek at chargen.matasano.com explains why simple, general-purpose hashing functions such as MD5, SHA1, SHA256 and SHA512 are poor password hashing choices.

Why? They are too fast--you can calculate 1,000,000 MD5 hashes a second per core with a modern computer, so brute force is feasible against most passwords people use.

Salting without key stretching only means that you cannot precompute the rainbow table, you need to build it ad hoc for that specific salt.

So the choice for PHP is either Crypt/Blowfish (BCrypt), Crypt/SHA256 or Crypt/SHA512. Or at least Crypt/MD5 (PHK). See www.php.net/manual/en/function.crypt.php

LexLythius
A: 

Out of this three algorythms the sha256 is way more safer, than the other two. But the good salting is much more important then the good choice of hash method.

You should use a fix salt, wich is long enough to prevent its cracking by brute force.

You should also use a random salt, wich can be stored as plain text in the db beside the hashed password. It can be quite short, it's main aim to prevent the attacker to find the common passwords(without random salt their hashes would be the same) and (if the attacker gets the fix salt) to prevent building site specific rainbow tables.

Sample code:

define('FIX_SALT','DVlDR%UZFdsf%!gfjSEFsz5ghdf');
(..)
$hashed_pass = hash('sha256',FIX_SALT.$plain_pass.$random_salt);

$random_salt should be a short random string, and can be stored as a plain text, as I mentioned above.

You shouldn't worry about the good speed of SHA256. There is no way that any attacker can generate even 2^128 hashes, it will be impossible in the next 20 years...

mimrock