Don'ts
- Don't limit what characters users can enter for passwords. Only idiots do this.
- Don't limit the length of a password. If your users want a sentence with supercalifragilisticexpialidocious in it, don't prevent them from using it.
- Never store your user's password in plain-text.
- Never email a password to your user except when they have lost theirs, and you sent a temporary one.
- Never, ever log passwords in any manner.
- Never hash passwords with SHA1 or MD5 or even SHA256! Modern crackers can exceed 60 and 180 billion hashes/second (respectively).
- Don't mix bcrypt and with the raw output of hash(), either use hex output or base64_encode it. (This applies to any input that may have a rogue \0 in it, which can seriously weaken security.)
Dos
- Use scrypt when you can; bcrypt if you cannot.
- Use PBKDF2 if you cannot use either bcrypt or scrypt, with SHA2 hashes.
- Reset everyone's passwords when the database is compromised.
- Implement a reasonable 8-10 character minimum length, plus require at least 1 upper case letter, 1 lower case letter, a number, and a symbol. This will improve the entropy of the password, in turn making it harder to crack. (See the "What makes a good password?" section for some debate.)
PHP
// Generate or return salted passwords function crypt2($password, $salt = "") { if($salt == "") { // A higher "cost" is more secure but consumes more processing power $cost = 10; // Create a random salt $salt = strtr(base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM)), '+', '.'); // Prefix information about the hash so PHP knows how to verify it later. // "$2a$" Means we're using the Blowfish algorithm. The following two digits are the cost parameter. $salt = sprintf("$2a$%02d$", $cost) . $salt; } // Hash the password with the salt $hash = crypt($password, $salt); return $hash; }
// Save password $hash = crypt2($user_password); // hash the password with salt dbquery("UPDATE users SET user_hash='".$hash."' WHERE user_id='1'");
// Login $sql = "SELECT user_hash FROM users WHERE user_loginname='Admin' LIMIT 1"; [...] $data = dbarray($result); if (hash_equals($data['user_hash'], crypt2($user_pass, $data['user_hash']))) { // Ok! }
[via]http://stackoverflow.com/questions/401656/secure-hash-and-salt-for-php-passwords/, https://alias.io/2010/01/store-passwords-safely-with-php-and-mysql/[/via]