While a sha-256 hash may seem unbreakable, for many input strings it takes seconds to crack. If you don't believe me, try the following or simply read this webpage:
$ python >>> import hashlib >>> print hashlib.sha256('megabrain').hexdigest() f53c51616f4c7943a4117afa1d0ba193f9af901c6ce175a2207a594e71c98ef5
Go to crackstation.net, paste the hash into the text area, click "crack hashes" and see it the admittedly super lame password cracked in a second. The basic concept behind the cracking is to precompute hashes for a lot of passwords, and doing reverse lookups - from hashcode to password. This way, it really does not make any difference how "good" your hashing algorithm is. This is not an attack against hashing algorithms, but an attack against common hashcodes. In the wild, you are more likely to encounter the hash of "megabrain" than the hash of "2f2f0a446f828f". While you should encourage everybody you meet to choose strong passwords, it is perhaps more sustainable to strengthen the security around weak passwords.
Salting
This is where salts come in, as weak passwords can be made stronger by salting. A salt is just a sequence of bytes, e.g. "c039b8f8a8..." that you concatenate with a password before computing a password hash. It is ineffective to use the same salt for all passwords, so by all means read this page to get the inside scoop on how to do this correctly.
$ python >>> os >>> import hashlib >>> password = 'megabrain' >>> salt = os.urandom(32) >>> stored_hash = hashlib.sha256(salt + password).hexdigest()
If you try to crack the stored_hash on crackstation.net, you will see that it is not successful. So the moral of the story is, a bad password + a good salt = a good password. Users only have to remember their (bad) password, while you should remember the good salt.
To authenticate as user with a salted password, you will again combine the salt and password before comparing to a stored hash:
>>> password_to_authenticate = 'megabrain' >>> if hashlib.sha256(salt + password_to_authenticate).hexdigest() == stored_hash: >>> print "User has been authenticated!" >>> else: >>> print "Wrong password!"