Php 我的Bcrypt加密足够安全吗?

Php 我的Bcrypt加密足够安全吗?,php,encryption,bcrypt,Php,Encryption,Bcrypt,我正在从事一个项目,在保存密码等方面需要一个非常先进的安全系统。所以我的问题是,这种保存密码的方法足够安全吗 这是我编程的方式: 当用户注册时,将根据以下详细信息创建salt: 唯一的用户ID(mySQL中的主键) 用户的电子邮件地址 当前(微)时间戳 网站配置中定义的一些随机键 这盐正被杂凑成一把钥匙 创建salt后,将使用Bcrypt对以下字符串进行散列:password+sha512 salt(工作级别10,($2a$10…) 然后跳过Bcrypt输出的前5个字符($2a$10),并将

我正在从事一个项目,在保存密码等方面需要一个非常先进的安全系统。所以我的问题是,这种保存密码的方法足够安全吗

这是我编程的方式:

  • 当用户注册时,将根据以下详细信息创建salt:
    • 唯一的用户ID(mySQL中的主键)
    • 用户的电子邮件地址
    • 当前(微)时间戳
    • 网站配置中定义的一些随机键
  • 这盐正被杂凑成一把钥匙
  • 创建salt后,将使用Bcrypt对以下字符串进行散列:password+sha512 salt(工作级别10,($2a$10…)
  • 然后跳过Bcrypt输出的前5个字符($2a$10),并将剩余的字符串保存到数据库中
  • 当用户尝试登录时,我首先检查用户名是否存在。如果是,我将使用check()函数检查密码是否正确

    我使用加密和检查

    你们能告诉我这种加密和验证的方式是否适合一个大项目吗

    问候,

    简·威廉

  • 从任何特定的输入中提取盐是绝对没有意义的。事实上,这只能削弱它。从与要散列的值相关的任何值派生的salt不是salt,它只是一种经过修改的散列算法。盐是完全(伪)随机噪声,周期。他们唯一的目的是使输入具有唯一性;最独特的值是随机噪声
  • 如果您从一个好的伪随机数生成器派生salt,则无需对其进行散列。这只能起到降低熵的作用
  • 您应该将整个结果存储在数据库中(包括
    $2a$10
    )。如果你做得很好,这个散列实际上是不可能暴力的。省略该信息只会使您的工作更加困难,但对潜在的攻击者来说,这并不会使工作更加困难

    存储该值可以让您查看创建哈希的算法,并随着时间的推移对其进行升级。随着硬件速度的提高,您应该增加算法的工作系数,并且随着更好的算法变得可用(hello scrypt!),您应该升级所使用的算法。其工作方式是在用户登录时检查哈希是否是使用最新和最大值创建的。此时,您就有机会重新设置明文密码并对其进行升级


  • 使用PHP的新版本或旧版本的垫片,这些版本经过了良好的测试,非常“高级”。

    首先,不要使用
    bcrypt
    。改用。这将增加离线暴力攻击的难度。[并不是说bcrypt不会,它们本质上是相同的,但PBKDF2支持任何哈希函数,而不仅仅是河豚]

    第二,这里是你应该如何做到这一点

  • 为盐随机生成(不基于任何内容)128位随机数
  • 将Salt作为自己的参数存储在数据库中。记住salt的目的是使相同的密码散列两次不会产生相同的结果
  • 选择一个好的散列算法。我的建议是使用SHA-256或SHA-512。这是您将用作
    PBKDF2
    函数的一部分的内容
  • 做一些研究,找出什么是一个好的轮数,使密码哈希花1秒。请记住,如果我们的密码密钥空间为96个字符,宽度至少为8个字符,并且每次排列都需要1秒的计算时间,那么攻击者就会哭泣。这其中很好的一点是,随着时间的推移,随着计算机速度的提高,您可以重新评估此值,并对哈希进行多次哈希运算,使其达到新的1秒要求。例如:假设在现代计算机上12轮SHA-256需要1秒。5年后,计算机的速度变得如此之快,12轮需要20毫秒。但是在硬件上16轮需要1秒。现在,只需将散列值再散列4次,即可将其保持在1秒。用户从不知道发生了这种情况,因为您不必要求他们更改密码
  • 当然,您可以将密码存储为阴影格式,但如果您使用的是数据库,则只需使用数据库字段即可。您解析字符串的速度比数据库要慢,因为它只知道给您什么

  • 现在我想指出你们系统中的一个定时攻击。如果您告诉攻击者用户名不存在,或者返回错误所需的时间与返回成功所需的时间不同(且更短),则可能发生旁道攻击。附加信息可以使攻击者更容易枚举系统上的用户帐户(如果用户名基于电子邮件,那么他们现在可以直接对用户进行网络钓鱼攻击)。

    首先,我要感谢你们的快速响应,让系统尽可能不易被黑客攻击对我来说非常重要

    根据你的建议,我制定了以下制度:

  • 当用户注册时,将创建一个唯一的哈希:

    $unique_hash=hash('sha512',一些已定义的安全密钥(在配置中).openssl_random_pseudo_bytes(50))

  • 第二步,创建一个盐:

    $salt=strtr(base64_编码(openssl_随机_伪_字节(50)),“+”,“.”)

  • 在另一个数据库中的另一个表中,这两个变量组合在一起,只有$unique_散列存储在users表的users行中

  • 然后我们创建加密密码,我使用此函数:

    <?php
    const COUNT = 8192; 
    const KEY_LENGTH = 254; 
    const ALGORITHM = 'sha512';
    
    public static function encrypt($password, $salt, $algorithm = PBKDF2::ALGORITHM, $count = PBKDF2::COUNT, $key_length = PBKDF2::KEY_LENGTH, $raw_output = false) {
    
    $algorithm = strtolower($algorithm);
    
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');
    
    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);
    
    $output = "";
    
    for($i = 1; $i <= $block_count; $i++) 
    {
    
        $last = $salt . pack("N", $i);
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
    
        for ($j = 1; $j < $count; $j++) 
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
    
        $output .= $xorsum;
    
    }
    
    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
    
     }
         ?>
    
    
    
  • 然后我们将此密码存储在默认用户表中

  • 最后一步;登录。当用户尝试登录时,首先我检查数据库中是否存在给定的用户名。当它出现时,我调用位于同一行的$unique_散列。既然我们需要盐,