如何在PHP中使用bcrypt进行散列密码?

Vil*_*lx- 1230 php passwords cryptography password-protection bcrypt

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

但是什么bcrypt呢?PHP没有提供任何此类功能,维基百科关于文件加密实用程序的唠叨和Web搜索只是揭示了不同语言的Blowfish的一些实现.现在Blowfish也可以通过PHP获得mcrypt,但是如何帮助存储密码?Blowfish是一种通用密码,它有两种工作方式.如果它可以加密,则可以解密.密码需要单向散列函数.

解释是什么?

And*_*ore 1043

bcrypt是一种散列算法,可以通过硬件进行扩展(通过可配置的轮数).它的缓慢和多轮确保攻击者必须部署大量资金和硬件才能破解您的密码.添加到每密码(bcrypt需要盐),你可以确定攻击几乎是不可行的,没有可笑的资金或硬件.

bcrypt使用Eksblowfish算法来散列密码.虽然EksblowfishBlowfish的加密阶段完全相同,但Eksblowfish的关键计划阶段确保任何后续状态都依赖于盐和密钥(用户密码),并且在不知道两者的情况下都不能预先计算任何状态.由于这个关键的区别,bcrypt是一种单向散列算法.如果不知道salt,rounds 和key(密码),则无法检索纯文本密码.[ 来源 ]

如何使用bcrypt:

使用PHP> = 5.5-DEV

密码散列函数现已直接构建到PHP> = 5.5中.您现在可以使用password_hash()创建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
Run Code Online (Sandbox Code Playgroud)

要针对现有哈希验证用户提供的密码,您可以使用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.';
}
Run Code Online (Sandbox Code Playgroud)

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

GitHub上有一个兼容库,它基于最初用C编写的上述函数的源代码创建,它提供相同的功能.安装兼容性库后,使用情况与上面相同(如果您仍在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;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

$bcrypt = new Bcrypt(15);

$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);
Run Code Online (Sandbox Code Playgroud)

或者,您也可以使用Portable PHP Hashing Framework.

  • @Mike:继续吧,正是出于这个原因! (53认同)
  • 请注意,这个答案虽然很好,但已开始显示其年龄.此代码(与依赖于`crypt()`的任何PHP实现一样)受5.3.7之前的安全漏洞影响,并且在5.3.7之后(非常轻微)低效 - 可以找到相关问题的详细信息[此处] ](http://www.php.net/security/crypt_blowfish.php).另请注意,新的[密码哈希API](http://php.net/password)([backwards compat lib](https://github.com/ircmaxell/password_compat))现在是实现bcrypt的首选方法您的应用程序中的密码哈希. (31认同)
  • @MichaelLang:好东西[`crypt()`](http://www.kernel.org/doc/man-pages/online/pages/man3/crypt.3.html)经过同行评审和验证.上面的代码调用PHP的`crypt()`,它调用POSIX [`crypt()`](http://www.kernel.org/doc/man-pages/online/pages/man3/crypt.3.html )功能.上面的所有代码更多的是在调用`crypt()`之前生成一个随机盐(它不必是加密安全的,盐不被认为是秘密).**也许你在打电话给狼之前应该自己做一点研究.** (18认同)
  • 对于任何认为他们需要修改getSalt函数中$ salt字符串的开头的人来说,这是不必要的.$ 2a $ __是CRYPT_BLOWFISH盐的一部分.来自文档:"Blowfish用盐散列如下:"$ 2a $",两位数的成本参数,"$"和字母表中的22位数字". (14认同)
  • @The Wicked Flea:很抱歉让你失望,但`mt_rand()`也是使用当前时间和当前进程ID播种的.请参阅`/ext/standard/php_rand.h`中的[`GENERATE_SEED()`(http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/standard/php_rand.h ?视图=标记). (7认同)
  • @Andrew,你介意我在我写的程序中使用这段代码吗? (7认同)
  • @Tchalvak:这就是为什么Stack Overflow有[编辑历史](http://stackoverflow.com/posts/6337021/revisions).你可以看到谁编辑了什么. (6认同)
  • @ircmaxell:[`mt_rand()`与5.3中的种子完全相同](https://github.com/php/php-src/blob/PHP-5.3/ext/standard/php_rand.h#L52)( `getmypid()`适用于所有系统......你应该知道,毕竟你是ZCE.可以说,这里加密安全盐的好处非常小; 在哈希中,盐不被认为是秘密.它只是迫使攻击者为每个密码生成一个不同的彩虹表(而不是为所有人使用相同的彩虹表).能够猜测下一个盐对攻击者没有任何好处(它是哈希中的纯文本). (6认同)
  • @andrewliu:`$ bcrypt-> verify($ passwordAsProvidedByTheUser,$ hashInTheDB);`如果返回'true`,则有效. (5认同)
  • @MatthewFlaschen:[`crypt()`](http://php.net/crypt)执行散列字符串的实际工作.它使用提供的盐(使用`$ 2a $ rounds $`标识符来确定它必须执行的舍入量. (4认同)
  • @MatthewFlaschen:再说一遍,不,[`crypt()`](http://php.net/crypt)负责处理.`bcrypt`算法的实现全部由[`crypt()`](http://php.net/crypt)处理,而不是由我上面的代码处理.我的代码只生成[`crypt()`](http://php.net/crypt)期望的格式的正确的盐,以便检查/散列字符串. (4认同)
  • @AndrewMoore,所以你期望`$ rounds`构造函数参数是base-2对数?这很好,除了这个名字有误导性.你应该更清楚它是圆计数的日志.因此我建议调用构造函数参数`$ log_2_rounds`. (3认同)
  • 疯狂的'itoa64`与使用`base64_encode`有什么关系吗?字符数相同,但值非常不同.前者更安全吗? (3认同)
  • @andrewliu确保你的数据库中的字段足够长以容纳密码hash`varchar(60)`我犯了一段时间的错误lol,并检查它的`true`是否使用`var_dump($ bcrypt-> verify( 'password',$ hash))` (3认同)
  • @PaŭloEbermann:`SHA256`和`SHA512`本身没有.`crypt()`正在采用密钥强化来达到同样的效果.你不能只有一轮`bcrypt`.密钥加强是Eksblowfish算法的一个组成部分. (2认同)
  • 我也同意@Tchalvak,如果你想让人们使用它,你应该把它变成一个开源库,正常的陷阱(VCS存储库,bug跟踪器,项目页面).然后,人们将更倾向于讨论和分析它的漏洞(并可能提交补丁来修复它们). (2认同)
  • @Ozzy看看http://www.openwall.com/phpass/,它有3 <= PHP <5.3的一些后备哈希方案 (2认同)
  • @JeffDavis salt已经是生成的哈希的组成部分. (2认同)
  • @AndyLobel:salt存在于完整哈希中,因此可以使用原始盐重新计算哈希值,以得出相同的结果.`$ 2A $ <roundCount> $ <盐> <computedHash>` (2认同)
  • @andrewliu:调用`$ bcrypt-> verify()`函数,将纯文本作为第一个参数,将存储在数据库中的哈希作为第二个参数. (2认同)
  • 哦,我的上帝.不要使用未上传到某个地方的加密代码,这些代码可以与您在加密时识别为真实权限的人员绑定,批准和同行评审.这不是关于开源与封闭源.无论上传到何处,都应提供经过审核和验证的来源的可见性.这是关于承认我们大多数人没有批评加密,而不是让盲人领导盲人.我真的应该依赖wiki上的匿名upvotes来告诉我是否要妥协我的客户数据?因为所有非加密专家都可以做到这一点. (2认同)
  • @AndrewMoore男,对不起.我一直在做研究.我只是犯了一个错误,误认为你的盐生成代码的哈希创建.也许你可以拉出盐代?当我想象人们习惯于复制/粘贴大量加密代码时,我会感到非常不安.需要注意的是要将你所做的事情与产生这场辩论的事情区分开来:http://news.ycombinator.com/item?id = 2654586 (2认同)
  • @ spankmaster79:*"两位数的成本参数是底层基于Blowfish的哈希算法的迭代计数的2对数,并且必须在04-31范围内,超出此范围的值将导致crypt()失败."* (2认同)
  • @Barmar你知道,我知道和许多其他"称职的程序员"都知道.但那些不知道的人呢?你需要在这里开箱/思考,并让自己穿上他们的鞋子一段时间;-) (2认同)

irc*_*ell 291

那么,你想使用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
    }
}
Run Code Online (Sandbox Code Playgroud)

真的,它的目标是非常简单.

资源:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

资源:

PasswordLib

这是一种稍微不同的密码散列方法.PasswordLib不是简单地支持bcrypt,而是支持大量的哈希算法.它主要用于需要支持与您可能无法控制的旧系统和不同系统兼容的环境中.它支持大量的哈希算法.并支持5.3.2+

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
    }
}
Run Code Online (Sandbox Code Playgroud)

参考文献:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

资源

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

关于BCrypt

如果您注意到,这些库中的每一个都返回一个字符串.那是因为BCrypt在内部工作.关于这一点,有很多答案.这是我写的一个选择,我不会在这里复制/粘贴,但链接到:

包起来

有很多不同的选择.你选择哪一个取决于你.但是,我强烈建议您使用上述库之一来为您处理此问题.

同样,如果你crypt()直接使用,你可能做错了什么.如果你的代码使用hash()(或md5()sha1()直接),你几乎可以肯定做错了什么.

只需使用图书馆......

  • 盐必须随机生成,但不需要来自安全的随机源.**盐不是秘密**.能够猜测下一个盐没有真正的安全影响; 只要它们来自足够大的数据池,为每个编码的密码生成不同的盐,你就可以了.请记住,如果您的哈希陷入困境,那么盐就是为了防止使用彩虹表.他们不是秘密. (7认同)
  • @AndrewMoore绝对正确!然而,盐必须具有足够的熵以在统计上独特.不仅在您的应用程序中,而且在所有应用程序中.所以`mt_rand()`有足够长的周期,但种子值只有32位.所以使用`mt_rand()`有效地限制你只有32位的熵.这要归功于生日问题意味着只有7k生成的盐(全局)有50%的碰撞几率.由于`bcrypt`接受128位盐,最好使用可以提供所有128位的源;-).(在128位,在2e19哈希发生碰撞的几率为50%)...... (7认同)
  • @AndrewMoore:绝对的.不是在争论.只是那个`mt_rand`和`uniqid`(因此`lcg_value`和`rand`)不是第一选择...... (4认同)

Ark*_*rkh 46

您将获得很多有关Rainbow Table的信息:您需要了解的有关安全密码方案便携式PHP密码哈希框架的信息.

目标是用一些缓慢的密码来散列密码,所以有人拿到你的密码数据库就会试图暴力破解它(检查密码的10毫秒延迟对你来说没什么,对于那些试图暴力破解它的人来说很多).Bcrypt很慢,可以与参数一起使用来选择它的速度.

  • 密码哈希用于防止一次攻击:有人窃取了您的数据库,并希望获得明文登录+密码. (41认同)
  • 强制执行您想要的任何内容,用户将设法搞砸并在多个事物上使用相同的密码.因此,您必须尽可能地保护它或实现一些不必存储任何密码(SSO,openID等)的东西. (7认同)
  • @Josh K.我鼓励你在通过phpass调整之后尝试破解一些简单的密码,这样在你的网络服务器上计算它需要1ms到10ms. (4认同)
  • @coreyward值得注意的是,做到这一点比没有阻止更有害; 这很容易被认为是"拒绝服务"的载体.只需开始在任何已知帐户上发送垃圾邮件,您就可以非常轻松地破坏许多用户.对攻击者进行tarpit(延迟)比直接拒绝访问更好,特别是如果它是付费用户. (4认同)
  • 同意.但是那种将qwerty用作密码的用户也是那种能够在他(和攻击者)可以轻松阅读的地方标记任何复杂的用户的用户.使用bcrypt完成的是当你的数据库违背你的意愿公开时,对于那些拥有像^ | $$和ZL6-这样的密码的用户来说,比你在一次通过中使用sha512更难. (3认同)
  • 您可以通过阻止在n大于合理尝试次数(如50)的n天中无法猜测其密码的"用户"来更轻松地防止暴力密码攻击. (2认同)

cor*_*ard 35

你可以使用PHP的crypt()函数和bcrypt创建一个单向哈希,并传入适当的Blowfish盐.整个等式中最重要的是A)算法没有被破坏,B)你正确地为每个密码加盐.不要使用全应用盐; 这会打开整个应用程序,从一组Rainbow表中进行攻击.

PHP - 加密函数

  • 这是正确的方法 - 使用PHP的`crypt()`函数,它支持几种不同的密码散列函数.确保你没有使用`CRYPT_STD_DES`或`CRYPT_EXT_DES` - 任何其他支持的类型都可以(并且包括名为`CRYPT_BLOWFISH`的bcrypt). (4认同)
  • SHA确实也有一个成本参数,通过'rounds'选项.使用它时,我也认为没有理由支持bcrypt. (4认同)
  • 实际上,单个SHA-1(或MD5)的密码仍然很容易暴力,有或没有盐(盐有助于彩虹表,而不是暴力强制).使用bcrypt. (3认同)
  • @Panique为什么?该算法称为*bcrypt*.`crypt`暴露了几个密码哈希,bcrypt对应于`CRYPT_BLOWFISH`常量.Bcrypt目前是`crypt`支持的最强算法,它支持的其他几个算法都非常弱. (3认同)

Jon*_*lka 33


编辑:2013.01.15 - 如果您的服务器支持它,请使用martinstoeckli的解决方案.


每个人都想让它变得更复杂.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);
}
Run Code Online (Sandbox Code Playgroud)

例:

$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
Run Code Online (Sandbox Code Playgroud)

我知道这很明显,但请不要使用"密码"作为密码.

  • 盐的创建可以改进(使用操作系统的随机源),否则它看起来不错.对于较新的PHP版本,最好使用`2y`而不是`2a`. (3认同)
  • 添加Base64编码并转换为自定义字母"bcrypt"使用.`mcrypt_create_iv(17,MCRYPT_DEV_URANDOM)`,`str_replace('+','.',base64_encode($ rawSalt))`,`$ salt = substr($ salt,0,22);` (2认同)

mar*_*kli 27

PHP 5.5版将内置支持BCrypt,函数password_hash()password_verify().实际上这些只是函数的包装器crypt(),并且使它更容易正确使用它.它负责生成安全的随机盐,并提供良好的默认值.

使用此功能的最简单方法是:

$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
Run Code Online (Sandbox Code Playgroud)

此代码将使用BCrypt(算法2y)对密码进行哈希处理,从OS随机源生成随机盐,并使用默认成本参数(此时为10).如果用户输入的密码与已存储的哈希值匹配,则第二行检查.

如果要更改成本参数,可以这样做,将成本参数增加1,将计算哈希值所需的时间加倍:

$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 11));
Run Code Online (Sandbox Code Playgroud)

"cost"参数相反,最好省略"salt"参数,因为该函数已经尽力创建加密安全盐.

对于PHP 5.3.7及更高版本,存在一个兼容包,来自制作该password_hash()功能的同一作者.对于5.3.7之前的PHP版本,不支持crypt()使用2yunicode安全BCrypt算法.人们可以用它代替它2a,这是早期PHP版本的最佳选择.

  • 读完之后,我的第一个想法是"你如何储存生成的盐"?在浏览文档之后,password_hash()函数最终生成一个字符串,用于存储加密方法,salt和生成的哈希.因此,它只是将所需的一切存储在一个字符串中,以使password_verify()函数正常工作.只是想提一下,因为当他们看到这个时它可能会帮助别人. (3认同)

小智 6

目前的想法:哈希应该是最慢的,而不是最快的.这抑制了彩虹表攻击.

也相关,但预防:攻击者永远不应无限制地访问您的登录屏幕.为了防止这种情况:设置一个IP地址跟踪表,记录每次匹配以及URI.如果在任何五分钟时间内有超过5次登录尝试来自同一IP地址,请进行解释.第二种方法是拥有一个双层密码方案,就像银行一样.在第二次通过时锁定故障会提高安全性.

摘要:使用耗时的哈希函数减慢攻击者的速度.此外,阻止对您的登录进行过多访问,并添加第二个密码层.

  • 在2012年的中途,这个答案仍然不稳定,缓慢的哈希算法如何防止彩虹表攻击?我以为随机字节范围盐了吗?我一直认为哈希算法的速度决定了他们可以针对他们在特定时间内获得的哈希发送多少次迭代.也绝不会在失败登录时阻止用户ATTEMPTS相信我的用户会厌倦,经常在某些网站上我需要登录近5次,有时候我还记得我的密码.第二次传递层也不起作用,但是可以使用手机代码进行两步验证. (4认同)

Syn*_*hro 6

另一种方法是使用scrypt,专门设计为在他的论文中优于colin Percival的bcrypt .在PECL中有一个scrypt PHP扩展.理想情况下,这个算法将被转换为PHP,以便可以为password_*函数指定(理想情况下为"PASSWORD_SCRYPT"),但那还没有.


She*_*Ali 5

对于OAuth 2密码:

$bcrypt = new \Zend\Crypt\Password\Bcrypt;
$bcrypt->create("youpasswordhere", 10)
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

378528 次

最近记录:

5 年,9 月 前