如何在 PHP 中使用 bcrypt 对密码进行哈希处理?
我不时听到使用 bcrypt 在 PHP 中存储密码,bcrypt 规则"的建议.
Every now and then I hear the advice "Use bcrypt for storing passwords in PHP, bcrypt rules".
但是什么是bcrypt
?PHP 不提供任何此类功能,Wikipedia 喋喋不休地谈论文件加密实用程序,Web 搜索仅显示 Blowfish 用不同的语言.现在 Blowfish 也可以通过 mcrypt
在 PHP 中使用,但是这对存储密码有什么帮助呢?Blowfish 是一种通用密码,它有两种工作方式.如果可以加密,就可以解密.密码需要单向散列函数.
But what is bcrypt
? PHP doesn't offer any such functions, Wikipedia babbles about a file-encryption utility and Web searches just reveal a few implementations of Blowfish in different languages. Now Blowfish is also available in PHP via mcrypt
, but how does that help with storing passwords? Blowfish is a general purpose cipher, it works two ways. If it could be encrypted, it can be decrypted. Passwords need a one-way hashing function.
解释是什么?
推荐答案
bcrypt
是一种散列算法,可通过硬件扩展(通过可配置的轮数).它的缓慢和多轮确保攻击者必须部署大量资金和硬件才能破解您的密码.添加到每个密码 salts (bcrypt
要求salts) 并且您可以确定,如果没有大量资金或硬件,攻击几乎是不可行的.
bcrypt
is a hashing algorithm which is scalable with hardware (via a configurable number of rounds). Its slowness and multiple rounds ensures that an attacker must deploy massive funds and hardware to be able to crack your passwords. Add to that per-password salts (bcrypt
REQUIRES salts) and you can be sure that an attack is virtually unfeasible without either ludicrous amount of funds or hardware.
bcrypt
使用 Eksblowfish 算法来散列密码.虽然 Eksblowfish 和 Blowfish 的加密阶段完全相同,但 Eksblowfish 的密钥调度阶段确保任何后续状态都依赖于 salt 和密钥(用户密码),并且在两者都不知情的情况下无法预先计算任何状态.由于这个密钥差异,bcrypt
是一种单向哈希算法.您无法在不知道 salt、rounds 和 key的情况下检索纯文本密码强>(密码).[来源]
bcrypt
uses the Eksblowfish algorithm to hash passwords. While the encryption phase of Eksblowfish and Blowfish are exactly the same, the key schedule phase of Eksblowfish ensures that any subsequent state depends on both salt and key (user password), and no state can be precomputed without the knowledge of both. Because of this key difference, bcrypt
is a one-way hashing algorithm. You cannot retrieve the plain text password without already knowing the salt, rounds and key (password). [Source]
密码哈希函数现已直接内置于 PHP >= 5.5.您现在可以使用 password_hash()
来创建 bcrypt
任何密码的哈希:
Password hashing functions have now been built directly into PHP >= 5.5. You may now use password_hash()
to create a bcrypt
hash of any password:
<?php
// Usage 1:
echo password_hash('rasmuslerdorf', PASSWORD_DEFAULT)."
";
// $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// For example:
// $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a
// Usage 2:
$options = [
'cost' => 11
];
echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."
";
// $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C
要根据现有哈希验证用户提供的密码,您可以使用 password_verify()
这样:
To verify a user provided password against an existing hash, you may use the password_verify()
as such:
<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';
if (password_verify('rasmuslerdorf', $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
使用 PHP >= 5.3.7, <5.5-DEV(还有 RedHat PHP >= 5.3.3)
兼容性库/wiki/GitHub" rel="noreferrer">GitHub 基于上述最初用 C 编写的函数的源代码创建,提供相同的功能.一旦安装了兼容性库,用法与上面相同(如果您仍在 5.3.x 分支上,则减去简写数组表示法).
Using PHP >= 5.3.7, < 5.5-DEV (also RedHat PHP >= 5.3.3)
There is a compatibility library on GitHub created based on the source code of the above functions originally written in C, which provides the same functionality. Once the compatibility library is installed, usage is the same as above (minus the shorthand array notation if you are still on the 5.3.x branch).
您可以使用 crypt()
函数来生成输入字符串的 bcrypt 哈希.此类可以自动生成盐并根据输入验证现有哈希.如果您使用的 PHP 版本高于或等于 5.3.7,强烈建议您使用内置函数或兼容库.此替代方案仅用于历史目的.
You can use crypt()
function to generate bcrypt hashes of input strings. This class can automatically generate salts and verify existing hashes against an input. If you are using a version of PHP higher or equal to 5.3.7, it is highly recommended you use the built-in function or the compat library. This alternative is provided only for historical purposes.
class Bcrypt{
private $rounds;
public function __construct($rounds = 12) {
if (CRYPT_BLOWFISH != 1) {
throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
}
$this->rounds = $rounds;
}
public function hash($input){
$hash = crypt($input, $this->getSalt());
if (strlen($hash) > 13)
return $hash;
return false;
}
public function verify($input, $existingHash){
$hash = crypt($input, $existingHash);
return $hash === $existingHash;
}
private function getSalt(){
$salt = sprintf('$2a$%02d$', $this->rounds);
$bytes = $this->getRandomBytes(16);
$salt .= $this->encodeBytes($bytes);
return $salt;
}
private $randomState;
private function getRandomBytes($count){
$bytes = '';
if (function_exists('openssl_random_pseudo_bytes') &&
(strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL is slow on Windows
$bytes = openssl_random_pseudo_bytes($count);
}
if ($bytes === '' && is_readable('/dev/urandom') &&
($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
$bytes = fread($hRand, $count);
fclose($hRand);
}
if (strlen($bytes) < $count) {
$bytes = '';
if ($this->randomState === null) {
$this->randomState = microtime();
if (function_exists('getmypid')) {
$this->randomState .= getmypid();
}
}
for ($i = 0; $i < $count; $i += 16) {
$this->randomState = md5(microtime() . $this->randomState);
if (PHP_VERSION >= '5') {
$bytes .= md5($this->randomState, true);
} else {
$bytes .= pack('H*', md5($this->randomState));
}
}
$bytes = substr($bytes, 0, $count);
}
return $bytes;
}
private function encodeBytes($input){
// The following is code from the PHP Password Hashing Framework
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (true);
return $output;
}
}
您可以像这样使用此代码:
You can use this code like this:
$bcrypt = new Bcrypt(15);
$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);
或者,您也可以使用便携式 PHP 哈希框架.
相关文章