如何在PHP中使用bcrypt来哈希密码?[重复]

14 浏览
0 Comments

如何在PHP中使用bcrypt来哈希密码?[重复]

这个问题已经有了答案

如何使用PHP的password_hash对密码进行hash和验证

每隔一段时间,我都会听到“在PHP中使用bcrypt来存储密码,bcrypt很厉害”的建议。

但是什么是bcrypt? PHP没有提供任何这样的功能,维基百科胡言乱语的谈论了一个文件加密工具,网络搜索只显示不同语言中Blowfish的几个实现。 现在通过mcrypt在PHP中也可以使用Blowfish,但这有助于存储密码吗? Blowfish是一种通用密码,它可以双向工作。如果可以加密,那么它也可以被解密。密码需要单向散列函数。

这是什么解释呢?

admin 更改状态以发布 2023年5月24日
0
0 Comments

所以,你想使用bcrypt?太棒了!然而,就像密码学的其他领域一样,你不应该自己做。如果你需要担心像管理密钥、存储盐或生成随机数这样的事情,你就错了。

原因很简单:处理bcrypt实在是太容易出错了。事实上,如果你看一看这个页面上的几乎每一份代码,你都会注意到它在至少一个常见的问题上存在问题。

承认吧,密码学很难。

把它留给专家吧。把它留给那些维护这些库的人。如果你需要做出决定,你就错了。

相反,只需使用一个库。根据你的要求,有几种选择。

这是一些更常见的API的详细介绍。

PHP 5.5 API - (可用于5.3.7+)

从PHP 5.5开始,引入了一个新的API来哈希密码。还维护有一个5.3.7+的兼容性库(由我维护)。它的好处是它是一个经过同行评审的,易于使用的实现。

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
    }
}

实际上,它的目标是非常简单的。

资源:

Zend\Crypt\Password\Bcrypt (5.3.2+)

这是另一个类似于PHP 5.5的API,具有类似的目的。

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
    }
}

资源:

PasswordLib

这是一种略微不同的密码哈希方法。它不仅支持bcrypt,还支持大量哈希算法。主要用于需要支持与遗留系统兼容的上下文。它支持大量哈希算法。且支持5.3.2以上版本的PHP。

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
    }
}

参考:

PHPASS

这是一种支持bcrypt且较强的算法的层,如果您无法访问 PHP>=5.3.2,它也会很有用。它可以支持 PHP 3.0+(但不支持bcrypt)。

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
    }
}

资源

注意:不要使用未托管在 openwall 上的 PHPASS 备选项,它们是不同的项目!!!

关于 BCrypt

你会发现,这些库每一个都返回单个字符串,这是因为 BCrypt 的内部工作原理。关于这个,有很多回答。这里有一些我写的选择,我不会复制/粘贴在这里,而是链接到下面:

总结

有很多不同的选择。您选择哪个取决于您。但是,我强烈建议您使用上述其中一个库来处理这些问题。

再次强调,如果你直接使用crypt(),你可能正在做一些错误的操作。如果你的代码直接使用hash()(或md5()sha1()),你几乎肯定在做错误的事情。

只需使用库即可...

0
0 Comments

bcrypt是一种散列算法,可以通过硬件进行扩展(通过可配置的轮数)。它的缓慢性和多轮确保攻击者必须投入大量资金和硬件才能破解您的密码。此外,使用每个密码的盐(bcrypt需要盐),您可以确信未经荒谬的资金或硬件,攻击几乎不可能发生。

bcrypt使用Eksblowfish算法对密码进行散列。虽然Eksblowfish和Blowfish的加密阶段完全相同,但Eksblowfish的密钥调度阶段确保任何后续状态都取决于盐和密钥(用户密码),并且没有状态可以在不知道这两者的情况下预先计算。因为这个关键的区别,bcrypt是一种单向散列算法。您不能在不知道盐、轮数和密钥(密码)的情况下检索纯文本密码。[来源]

如何使用bcrypt:

使用PHP >= 5.5-DEV

现在,密码散列函数已直接集成到PHP >= 5.5中。您现在可以使用password_hash()创建任何密码的bcrypt哈希:http://php.net/password_hash

 11
];
echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n";
// $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C

要验证用户提供的密码是否与现有哈希值匹配,可以使用password_verify()进行如下操作:


使用 PHP >= 5.3.7,< 5.5-DEV(也适用于 RedHat PHP >= 5.3.3)

GitHub 上有一个基于以上函数的原始 C 代码创建的 兼容性库,提供相同的功能。安装兼容性库后,使用与上面相同(如果仍然使用 5.3.x 分支,则不包括简写数组符号)。

使用 PHP < 5.3.7(已弃用)

您可以使用 crypt() 函数生成输入字符串的 bcrypt 哈希。此类可以自动生成盐并验证现有哈希是否与输入匹配。 如果您使用的是高于或等于 5.3.7 版本的 PHP,则强烈建议使用内置函数或兼容库。此选项仅供历史记录。

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;
  }
}

您可以像这样使用此代码:

$bcrypt = new Bcrypt(15);
$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);

另外,您也可以使用 Portable PHP Hashing Framework

0