你如何使用 bcrypt 在 PHP 中散列密码? [英] How do you use bcrypt for hashing passwords in PHP?

查看:28
本文介绍了你如何使用 bcrypt 在 PHP 中散列密码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Every now and then I hear the advice "Use bcrypt for storing passwords in PHP, bcrypt rules".

但是什么是bcrypt?PHP 不提供任何此类功能,维基百科喋喋不休地谈论文件加密实用程序,而网络搜索只揭示了 河豚 不同语言.现在 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 要求盐),并且您可以确定,如果没有可笑的资金或硬件,攻击实际上是不可行的.

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 算法来散列密码.虽然 EksblowfishBlowfish 的加密阶段完全相同,Eksblowfish 的关键调度阶段确保任何后续状态都依赖于盐和密钥(用户密码),并且在不知道两者的情况下无法预先计算任何状态.由于此密钥差异,bcrypt 是一种单向哈希算法.如果不知道盐、轮数和密钥,您将无法检索纯文本密码.强>(密码).[来源]

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 哈希值.这个类可以自动生成盐并根据输入验证现有的哈希值.如果您使用的是高于或等于5.3.7的PHP版本,强烈建议您使用内置函数或compat库.此替代方案仅用于历史目的.

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 哈希框架.

这篇关于你如何使用 bcrypt 在 PHP 中散列密码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆