如何在PHP中使用bcrypt对密码进行哈希处理?
我不时听到这样的建议:“使用bcrypt在PHP中存储密码,使用bcrypt规则” 但是什么是如何在PHP中使用bcrypt对密码进行哈希处理?,php,passwords,cryptography,password-protection,bcrypt,Php,Passwords,Cryptography,Password Protection,Bcrypt,我不时听到这样的建议:“使用bcrypt在PHP中存储密码,使用bcrypt规则” 但是什么是bcrypt?PHP不提供任何此类功能,Wikipedia喋喋不休地谈论一个文件加密实用程序,Web搜索只是揭示了一些不同语言的实现。现在,Blowfish也可以通过mcrypt在PHP中使用,但是这对存储密码有什么帮助呢?河豚是一种通用密码,它有两种工作方式。如果可以加密,就可以解密。密码需要一个单向散列函数 解释是什么?您将在或中获得大量信息 我们的目标是用一些慢的东西对密码进行散列,这样,获得密码
bcrypt
?PHP不提供任何此类功能,Wikipedia喋喋不休地谈论一个文件加密实用程序,Web搜索只是揭示了一些不同语言的实现。现在,Blowfish也可以通过mcrypt
在PHP中使用,但是这对存储密码有什么帮助呢?河豚是一种通用密码,它有两种工作方式。如果可以加密,就可以解密。密码需要一个单向散列函数
解释是什么?您将在或中获得大量信息
我们的目标是用一些慢的东西对密码进行散列,这样,获得密码数据库的人就会在尝试暴力破解密码时死亡(检查密码延迟10毫秒对你来说毫无意义,对于试图暴力破解密码的人来说,这是一个很大的问题)。速度很慢,可以与参数一起使用以选择速度有多慢。您可以使用PHP的
crypt()
函数通过bcrypt创建单向哈希,并传入适当的河豚盐。整个等式中最重要的一点是A)算法没有被破坏,B)您正确地加密了每个密码。不要使用应用范围广泛的盐;这将打开您的整个应用程序,使其受到来自单个Rainbow表集的攻击
bcrypt
是一种哈希算法,可通过硬件(通过可配置的轮数)进行扩展。它的缓慢和多轮确保攻击者必须部署大量资金和硬件才能破解您的密码。再加上每个密码(bcrypt
requirementsalts),您可以确定,如果没有巨额资金或硬件,攻击几乎是不可行的
bcrypt
使用Eksblowfish算法散列密码。虽然Eksblowfish和Blowfish的加密阶段完全相同,但Eksblowfish的密钥调度阶段确保任何后续状态都依赖于salt和密钥(用户密码),并且在不了解两者的情况下,无法预计算任何状态由于此密钥差异,bcrypt
是一种单向散列算法。在不知道salt的情况下,无法检索纯文本密码,将和密钥(密码)舍入。[]
如何使用bcrypt:
使用PHP>=5.5-DEV
密码散列函数。您现在可以使用创建任何密码的bcrypt
哈希:
<?php
// Usage 1:
echo password_hash('rasmuslerdorf', PASSWORD_DEFAULT)."\n";
// $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// For example:
// $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a
// Usage 2:
$options = [
'cost' => 11
];
echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n";
// $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C
使用PHP>=5.3.7,<5.5-DEV(也称为RedHat PHP>=5.3.3)
基于最初用C编写的上述函数的源代码创建了一个on,它提供了相同的功能。安装兼容性库后,用法与上面相同(如果您仍在5.3.x分支上,则减去速记数组符号)
使用PHP<5.3.7(已弃用)
您可以使用crypt()
函数来生成输入字符串的bcrypt哈希。此类可以自动生成SALT并根据输入验证现有哈希如果您使用的PHP版本高于或等于5.3.7,强烈建议您使用内置函数或compat库。此备选方案仅用于历史目的
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;
}
}
或者,您也可以使用。当前的想法:哈希应该是可用的最慢的,而不是最快的。这将抑制攻击 同样相关但也是预防性的:攻击者永远不应该对您的登录屏幕拥有无限的访问权限。为了防止这种情况:设置一个IP地址跟踪表,记录每次命中以及URI。如果在任何五分钟内有5次以上的登录尝试来自同一IP地址,请阻止并解释。第二种方法是像银行一样采用两层密码方案。在第二次通过时锁定故障可以提高安全性 摘要:通过使用耗时的哈希函数来降低攻击者的攻击速度。另外,阻止过多的登录访问,并添加第二层密码。
编辑:2013.01.15-如果您的服务器支持,请改用
每个人都想让事情变得更复杂。crypt()函数完成了大部分工作
function blowfishCrypt($password,$cost)
{
$chars='./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$salt=sprintf('$2y$%02d$',$cost);
//For PHP < PHP 5.3.7 use this instead
// $salt=sprintf('$2a$%02d$',$cost);
//Create a 22 character salt -edit- 2013.01.15 - replaced rand with mt_rand
mt_srand();
for($i=0;$i<22;$i++) $salt.=$chars[mt_rand(0,63)];
return crypt($password,$salt);
}
我知道这应该是显而易见的,但请不要使用“password”作为密码。5.5版PHP将内置对BCrypt、函数和密码的支持。事实上,这些只是函数的包装,应该更容易正确使用它。它负责生成安全的随机盐,并提供良好的默认值 使用此功能的最简单方法是:
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
此代码将使用BCrypt(algorithm2y
)散列密码,从OS随机源生成随机salt,并使用默认成本参数(目前为10)。第二行检查用户输入的密码是否与已存储的哈希值匹配
如果要更改成本参数,可以这样做,将成本参数增加1,使计算哈希值所需的时间加倍:
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 11));
与的“cost”
参数不同,最好省略的“salt”
参数,因为函数已经尽力创建加密安全的salt
对于PHP版本5.3.7及更高版本,存在一个,来自生成
密码\u hash()函数的同一作者。对于5.3.7之前的PHP版本,不支持使用unicode安全BCrypt算法的crypt()
。可以用2a
代替它,这是早期PHP版本的最佳替代方案。那么,您想使用bcrypt吗<太棒了
但是,与加密的其他领域一样,您不应该自己做。如果您需要担心管理密钥、存储盐或生成随机数之类的事情,那么您就错了
T
$hash=blowfishCrypt('password',10); //This creates the hash
$hash=blowfishCrypt('password',12); //This creates a more secure hash
if(crypt('password',$hash)==$hash){ /*ok*/ } //This checks a password
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 11));
function register($username, $password) {
$hash = password_hash($password, PASSWORD_BCRYPT);
save($username, $hash);
}
function login($username, $password) {
$hash = loadHashByUsername($username);
if (password_verify($password, $hash)) {
//login
} else {
// failure
}
}
function register($username, $password) {
$bcrypt = new Zend\Crypt\Password\Bcrypt();
$hash = $bcrypt->create($password);
save($user, $hash);
}
function login($username, $password) {
$hash = loadHashByUsername($username);
$bcrypt = new Zend\Crypt\Password\Bcrypt();
if ($bcrypt->verify($password, $hash)) {
//login
} else {
// failure
}
}
function register($username, $password) {
$lib = new PasswordLib\PasswordLib();
$hash = $lib->createPasswordHash($password, '$2y$', array('cost' => 12));
save($user, $hash);
}
function login($username, $password) {
$hash = loadHashByUsername($username);
$lib = new PasswordLib\PasswordLib();
if ($lib->verifyPasswordHash($password, $hash)) {
//login
} else {
// failure
}
}
function register($username, $password) {
$phpass = new PasswordHash(12, false);
$hash = $phpass->HashPassword($password);
save($user, $hash);
}
function login($username, $password) {
$hash = loadHashByUsername($username);
$phpass = new PasswordHash(12, false);
if ($phpass->CheckPassword($password, $hash)) {
//login
} else {
// failure
}
}
$hash = password_hash('mypassword', PASSWORD_ARGON2I);
$hash = password_hash('mypassword', PASSWORD_ARGON2ID);
$hash = sodium_crypto_pwhash_str(
'mypassword',
SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);
$bcrypt = new \Zend\Crypt\Password\Bcrypt;
$bcrypt->create("youpasswordhere", 10)