我不时听到这样的建议:"使用bcrypt在PHP中存储密码,使用bcrypt规则".

但什么是bcrypt?PHP不提供任何这样的功能,维基百科喋喋不休地谈论一个文件加密实用程序,而Web搜索只揭示了Blowfish在不同语言中的一些实现.现在,Blowfish也可以通过mcrypt在PHP中使用,但这对存储密码有什么帮助呢?河豚是一种通用密码,它有两种工作方式.如果可以加密,就可以解密.密码需要一个单向散列函数.

原因是什么?

推荐答案

bcrypt是可用硬件(通过可配置的轮数)扩展的散列算法.它的缓慢和多轮次确保攻击者必须部署大量资金和硬件才能破解您的密码.再加上每个密码salts(bcrypt需要盐),你可以肯定,如果没有荒谬的资金或硬件,攻击实际上是不可行的.

bcrypt使用Eksblowfish算法对口令进行哈希处理.虽然加密阶段EksblowfishBlowfish完全相同,但是Eksblowfish的密钥调度阶段确保任何后续状态都取决于盐和密钥(用户密码),并且在不知道两者的情况下无法预计算出任何状态.Because of this key difference, 101 is a one-way hashing algorithm.在不知道SALT的情况下无法检索明文密码,循环and key(密码).[Source][font=宋体]

How to use bcrypt:

使用PHP>=5.5-DEV

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)."\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

要根据现有哈希值验证用户提供的密码,可以使用password_verify():

<?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.';
}

Using PHP >= 5.3.7, < 5.5-DEV (also RedHat PHP >= 5.3.3)

根据上述函数最初用C编写的源代码创建了一个compatibility library on GitHub,它提供了相同的功能.一旦安装了兼容性库,使用方法与上面相同(如果您仍然使用5.3.x分支,则go 掉速记数组符号).

Using PHP < 5.3.7 (DEPRECATED)

可以使用crypt()函数生成输入字符串的bcrypt哈希.此类可以自动生成SALT,并根据输入验证现有哈希.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.本备选方案仅用于历史目的.

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.

Php相关问答推荐

Laravel变形 map 不适用于扩展模型

此行动未经授权.升级Laravel时

为什么这个方法调用用引号和花括号包裹?

如何发送woocommerce订单跟踪码与短信

致命错误:无法使用简单的php博客重新声明spl_autoload_Register()

如何限制WordPress自定义分类术语页面中的术语数量

是否重新排序多维数组元素以将所有子数组中的子数组移动到元素列表的底部?

针对给定产品类别的WooCommerce计数审核

带Redhat php curl的http_code 0

除WooCommerce中的特定国家/地区外,有条件地要求填写邮政编码 checkout 字段

使用其ID查询和捕获与订单相关的其他详细信息的shopware 6方法

在 Botiga 主题模板中添加复选框到政策行.Woocommerce

在WooCommerce可变产品中显示所选变体的自定义字段

WooCommerce订单支付页面上的附加支付订单按钮

Woocommerce单个添加到购物车页面中的产品动态定价

$_SERVER 超全局变量在 PHP 中是否保证可写?

如何使用相同的变量使函数参数对于数组和字符串都是可选的

每个发布请求 Laravel 9 的 CSRF 令牌不匹配

PHP 中的正则表达式,具有字符范围,但不包括特定字符

PHP 自动函数参数和变量