Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/240.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 散列密码,从坏方法到现在最安全_Php_Security_Hash_Passwords - Fatal编程技术网

Php 散列密码,从坏方法到现在最安全

Php 散列密码,从坏方法到现在最安全,php,security,hash,passwords,Php,Security,Hash,Passwords,我脑子里只有一个关于社区的简单问题。曾几何时,当我开始编程时,我使用md5对密码进行哈希处理,后来发现md5很容易被破解,我应该使用salt使其安全 我对md5没有信心,想使用sha1、sha256、SH512加密。但问题是现在我有加密形式的密码 md5("password"+"salt") 当时我不知道用户的密码,所以我做了什么 sha1(md5("password"+"salt")) 现在,在这个领域工作了几次之后,我发现sha1也不太安全,并且被破坏了。我应该做的是使用bcrypt()

我脑子里只有一个关于社区的简单问题。曾几何时,当我开始编程时,我使用md5对密码进行哈希处理,后来发现md5很容易被破解,我应该使用salt使其安全

我对md5没有信心,想使用sha1、sha256、SH512加密。但问题是现在我有加密形式的密码

md5("password"+"salt")
当时我不知道用户的密码,所以我做了什么

sha1(md5("password"+"salt"))
现在,在这个领域工作了几次之后,我发现sha1也不太安全,并且被破坏了。我应该做的是使用bcrypt()使密码安全

所以从现在起我将使用

 crypt(sha1(md5("password"+"salt")))
密码现在非常安全,但主要问题仍然是它用于创建哈希值的时间始终大于使用bcrypt(“密码”)的时间

现在我想说的是,假设bcrypt被黑客攻击,并且被发现被破坏了,那么在未来会出现新的加密功能,它更安全,更安全。而这种从旧值创建密码的方法总是很耗时

解决这个问题的办法是什么。据我所知,向用户发送更改密码的邮件并不总是100%成功的。 另一件事是在数据库中添加一个新字段来存储新的散列值,如果所有字段都已填充,则从数据库中删除md5值

那么这件事会继续下去吗,或者你们有什么解决办法。:)

解决此问题的方法:

PHP5.5中新的安全密码哈希API

PHP5.5刚刚接受了一个新的易于使用的密码哈希API的RFC。由于RFC本身是相当技术性的,并且大多数示例代码都是您不应该使用的,因此我想非常快速地概述一下新API:

为什么我们需要新的API?

每个人都知道应该使用bcrypt对他们的密码进行散列,但是仍然有很多开发人员使用不安全的md5或sha1散列(看看最近的密码泄漏)。其中一个原因是crypt()API难以使用,而且很容易出现编程错误

通过添加一个新的、非常简单易用的API,我们希望将更多的开发人员推向bcrypt

如何散列密码

创建密码哈希最简单不过了:

  $hash = password_hash($password, PASSWORD_DEFAULT);
这将使用默认算法(当前为bcrypt)、默认加载因子(当前为10)和自动生成的salt创建密码哈希。所使用的算法和salt也将是结果哈希的一部分,因此您根本不需要担心它们;)

如果您不想坚持默认设置(将来可能会更改),您还可以自己提供算法和负载系数:

$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
验证密码

验证密码同样简单:

<?php
// $password from user, $hash from database
if (password_verify($password, $hash)) {
    // password valid!
} else {
    // wrong password :(
}
实际上,如果使用得当,仍然被认为是完全安全的密码散列。虽然存在针对MD5的实际攻击,这使得它对于数字签名之类的东西不安全,但破坏密码散列将需要一个密码,而目前已知的所有针对MD5的此类攻击都纯粹是理论上的

(这就是说,套用Bruce Schneier的话,“攻击只会变得更好”,因此开始从MD5转移到更可靠的散列函数,例如or,当然不是一个坏主意,即使您还不需要这样做。)

问题在于,MD5本身不适合对密码进行哈希处理,原因有两个,这两个都是经过深思熟虑的设计特性(其他哈希函数如SHA-2和SHA-3也有此特性):

  • MD5是确定性的,这意味着用MD5散列相同的输入总是产生相同的输出

    这是密码散列的一个问题,因为有人可以(事实上)编译一个包含常见(但不太常见)密码的MD5散列的大型数据库,允许任何知道在这些数据库中找到的任何密码的普通MD5散列的人只需查找它并找到原始密码

    解决方案很简单,您已经知道了:在散列之前将密码与随机密码结合起来,并将salt作为最终散列的一部分,以便以后可以使用它来验证密码。由于有足够多的可能的盐(比如说,至少几十亿)可供随机选择,编译哈希数据库变得不可能,因为任何一个密码都可以哈希成数十亿个不同的值。方便地说,这也意味着,即使您碰巧有两个用户使用相同的密码,也不可能仅通过查看散列就知道这一点

  • MD5是快速的。通常,这被认为是一件好事,但在密码散列中,结果表明,使过程过快只会帮助攻击者:合法用户并不真正关心散列密码是需要10纳秒还是10毫秒,然而,如果攻击者试图通过暴力破解数百万个密码来猜密码,那么每次哈希计算都会减少几分之一纳秒

    同样,解决方案简单且众所周知:只需将密码重新散列数千次(或更多次),以降低计算速度。这些方法甚至是标准化的方法,比如方法。或者,也可以使用一个专门构建的密码散列函数,比如or,它通常内置了satting和可调整的迭代计数

  • 无论如何。。。所有这些的要点是,事实上,计算您的密码散列,例如

    hash = salt + bcrypt( sha1( md5( password + salt ) ) )
    
    很好,即使有点复杂。而且,对于这一系列的散列,几乎所有的时间都被bcrypt占用,因为它是三个故意设计得很慢的散列函数中唯一的一个。因此,应该没有明显的速度差异
    hash = salt + bcrypt( sha1( md5( password + salt ) ) )
    
    $passwordFromDatabase = "0d107d09f5bbe40cade3de5c71e9e9b7"; // md5  hash of "letmein"
    $passwordFromForm = $_POST['password']; // $_POST['password'] == "letmein"
    
    if(password_needs_rehash($passwordFromDatabase, PASSWORD_BCRYPT, ["cost" => 12]) && md5($passwordFromForm) === $passwordFromDatabase){
        // generate new password
        $newPasswordHash = password_hash($passwordFromForm, PASSWORD_BCRYPT, ["cost" => 12]);
        // update hash from database - replace old hash $passwordFromDatabase with new hash $newPasswordHash
        // after update login user
        if(password_veryfi($passwordFromForm, $newPasswordHash)){
            // user has logged in successfully and hash was updated
            // redirect to user area
        }else{
            // ups something went wrong Exception
        }
    }else{
        if($password_veryfi($passwordFromForm, $passwordFromDatabase)){
            // user password hash from database is already BCRYPTed no need to rehash
            // user has logged in successfully
            // redirect to user area
        }else{
            // wrong password
            // no access granted - stay where you are
        }
    }
    
    <?php
    /**
     * This code will benchmark your server to determine how high of a cost you can
     * afford. You want to set the highest cost that you can without slowing down
     * you server too much. 8-10 is a good baseline, and more is good if your servers
     * are fast enough. The code below aims for ≤ 50 milliseconds stretching time,
     * which is a good baseline for systems handling interactive logins.
     */
    $timeTarget = 0.50; // 500 milliseconds 
    
    $cost = 8; //start to measure from cost = 8
    do {
        $cost++;
        $start = microtime(true);
        password_hash("Ajd_hsk-K87&", PASSWORD_BCRYPT, ["cost" => $cost]);
        $end = microtime(true);
    } while (($end - $start) < $timeTarget);
    
    echo "Appropriate Cost Found: " . $cost . "\n";
    ?>
    
    Appropriate Cost Found: 13 //this result will be different based on your server machine.