- Do not store password as plain text
- Do not try to invent your own password security
- Do not ‘encrypt’ passwords
- Do not use MD5
- Do not use a single site-wide salt
- What you should do
- Use a cryptographically strong hashing function like bcrypt (see PHP's crypt() function).
- Use a random salt for each password.
- Use a slow hashing algorithm to make brute force attacks practically impossible.
- For bonus points, regenerate the hash every time a users logs in.
$username = 'Admin'; $password = 'gf45_gdf#4hg'; // 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; // Value: // $2a$10$eImiTXuWVxfM37uY4JANjQ== // Hash the password with the salt $hash = crypt($password, $salt); // Value: // $2a$10$eImiTXuWVxfM37uY4JANjOL.oTxqp7WylW7FCzx2Lc7VLmdJIddZq
In the above example we turned a reasonably strong password into a hash that we can safely store in a database. The next time the user logs in we can validate the password as follows:
$username = 'Admin'; $password = 'gf45_gdf#4hg'; // For brevity, code to establish a database connection has been left out $sth = $dbh->prepare(' SELECT hash FROM users WHERE username = :username LIMIT 1 '); $sth->bindParam(':username', $username); $sth->execute(); $user = $sth->fetch(PDO::FETCH_OBJ); // Hashing the password with its hash as the salt returns the same hash if ( hash_equals($user->hash, crypt($password, $user->hash)) ) { // Ok! }
A few additional tips to prevent user accounts from being hacked:
- Limit the number of failed login attempts.
- Require strong passwords.
- Do not limit passwords to a certain length (remember, you're only storing a hash so length doesn't matter).
- Allow special characters in passwords, there is no reason not to.
注意:hash_equals (PHP 5 >= 5.6.0) 如果你的php版本 phpversion()
不够,可以尝试使用下面的代码
原文:https://alias.io/2010/01/store-passwords-safely-with-php-and-mysql/
password_compat
This library requires PHP >= 5.3.7
OR a version that has the $2y
fix backported into it (such as RedHat provides). Note that Debian's 5.3.3 version is NOT supported.
使用前,用下面代码测试当前域名是否可以用这个password_compat
<?php require "lib/password.php"; echo "Test for functionality of compat library: " . (PasswordCompatbinarycheck() ? "Pass" : "Fail"); echo "n";
Usage
Creating Password Hashes
To create a password hash from a password, simply use the password_hash
function.
$hash = password_hash($password, PASSWORD_BCRYPT);
Note that the algorithm that we chose is PASSWORD_BCRYPT
. That's the current strongest algorithm supported. This is the BCRYPT
crypt algorithm. It produces a 60 character hash as the result.
BCRYPT
also allows for you to define a cost
parameter in the options array. This allows for you to change the CPU cost of the algorithm:
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10));
That's the same as the default. The cost can range from 4
to 31
. I would suggest that you use the highest cost that you can, while keeping response time reasonable (I target between 0.1 and 0.5 seconds for a hash, depending on use-case).
Another algorithm name is supported:
PASSWORD_DEFAULT
This will use the strongest algorithm available to PHP at the current time. Presently, this is the same as specifying PASSWORD_BCRYPT
. But in future versions of PHP, it may be updated to use a stronger algorithm if one is introduced. It can also be changed if a problem is identified with the BCRYPT algorithm. Note that if you use this option, you are strongly encouraged to store it in a VARCHAR(255)
column to avoid truncation issues if a future algorithm increases the length of the generated hash.
It is very important that you should check the return value of password_hash
prior to storing it, because a false
may be returned if it encountered an error.
Verifying Password Hashes
To verify a hash created by password_hash
, simply call:
if (password_verify($password, $hash)) { /* Valid */ } else { /* Invalid */ }
That's all there is to it.
Rehashing Passwords
From time to time you may update your hashing parameters (algorithm, cost, etc). So a function to determine if rehashing is necessary is available:
if (password_verify($password, $hash)) { if (password_needs_rehash($hash, $algorithm, $options)) { $hash = password_hash($password, $algorithm, $options); /* Store new hash in db */ } }
项目地址:https://github.com/ircmaxell/password_compat
下载:password_compat-master
转自:PHP 加密用户密码 How to store passwords safely with PHP and MySQL