哈希密码,从破碎方法到现在最安全

Abh*_*hek 6 php security passwords hash

我脑子里只有一个简单的问题就是社区.曾几何时,当我开始编程时,我使用md5进行散列密码,后来发现md5很容易破解,我应该使用salt来保证其安全.

比我对md5没信任,想用sha1,sha256,sha512加密.但问题是现在我有加密形式的密码

md5("password"+"salt")
Run Code Online (Sandbox Code Playgroud)

那时我不知道用户的密码.所以我做了什么

sha1(md5("password"+"salt"))
Run Code Online (Sandbox Code Playgroud)

现在经过几次在这个领域,我发现sha1也不太安全,而且我应该怎么做才能使用bcrypt()来保证密码安全.

所以从现在起我将使用

 crypt(sha1(md5("password"+"salt")))
Run Code Online (Sandbox Code Playgroud)

密码现在非常安全,但主要问题仍然是它将用于创建哈希值的时间总是大于使用bcrypt("密码")

现在我要说的是假设bcrypt被黑客攻击并被发现被破坏,并且将来会出现更加安全的新加密功能.这样,从旧值创建密码总是很费时间.

什么可以解决这个问题.因为我知道邮件用户更改密码并不总是100%成功.另一件事是在数据库中添加一个存储新散列值的新字段,如果填充了所有字段,则从db中移除md5值.但是以这种方式事物仍然可以看到先前的散列值.

所以这件事情会发生,或者你们有一些解决方案.:)

Joh*_*nde 7

PHP 5.5引入了解决此问题的密码API:

PHP 5.5中新的Secure Password Hashing API

PHP 5.5刚刚接受了一个新的简单易用的密码散列API的RFC.由于RFC本身是技术性的,并且大多数示例代码都是您不应该使用的,我想快速概述新API:

为什么我们需要一个新的API?

每个人都知道你应该使用bcrypt对其密码进行哈希处理,但仍然有相当多的开发人员使用不安全的md5或sha1哈希(只看最近的密码泄漏).其中一个原因是crypt()API非常难以使用,并且非常容易出现编程错误.

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

如何哈希密码

创建密码哈希不能比这更简单:

  $hash = password_hash($password, PASSWORD_DEFAULT);
Run Code Online (Sandbox Code Playgroud)

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

如果您不想坚持使用默认值(将来可能会更改),您还可以自己提供算法和加载因子:

$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
Run Code Online (Sandbox Code Playgroud)

验证密码

验证密码同样简单:

<?php
// $password from user, $hash from database
if (password_verify($password, $hash)) {
    // password valid!
} else {
    // wrong password :(
}
Run Code Online (Sandbox Code Playgroud)

请记住:salt和算法是哈希的一部分,因此您无需单独提供它们.

重新密码

随着时间的推移,您可能希望更改密码哈希算法或加载因子,或者PHP可能会将默认值更改为更安全.在这种情况下,应使用新选项创建新帐户,并在登录时重新显示现有密码(您只能在登录时执行此操作,因为您需要使用原始密码进行重新扫描).

这样做也很简单:

<?php
function password_verify_with_rehash($password, $hash) {
    if (!password_verify($password, $hash)) {
        return false;
    }

    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        $hash = password_hash($password, PASSWORD_DEFAULT);

        // update hash in database
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码片段将使您的哈希值与PHP默认值保持同步.但是,您也可以再次指定自定义选项,例如password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 12']).

旧版PHP版本的兼容性层

新的API只会在PHP 5.5中引入,但您现在已经可以使用相同API的PHP实现了!升级到5.5后,兼容性实现将自动禁用.


Ilm*_*nen 6

事实上,MD5,如果使用得当,仍然被认为是密码散列万无一失.虽然确实存在针对MD5的实际碰撞攻击,这使得它对诸如数字签名之类的东西不安全,但是破解密码散列将需要前映像攻击,并且所有当前已知的针对MD5的这种攻击纯粹是理论上的.

(也就是说,套用布鲁斯,"攻击永远只能变得更好",所以开始从MD5转移到更值得信赖的散列函数,如SHA-2SHA-3 ,肯定不是一个坏主意,即使你不"我还需要这样做.)

问题在于单独的 MD5 不适用于散列密码有两个原因,这两个原因实际上都是有意设计的功能(并且由SHA-2和SHA-3等其他散列函数共享):

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

    这是密码散列的一个问题,因为有人可能(实际上有些人)只编译一个庞大的MD5哈希常见(而不是那么常见)密码的数据库,允许任何知道任何密码的普通MD5哈希的人在这些数据库中找到它只是查找并找到原始密码.

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

  2. MD5 很快.通常这被认为是一件好事,但在密码散列中,事实证明,使进程过快主要只是帮助攻击者:合法用户并不真正关心是否散列密码需要10纳秒或10毫秒,而攻击者则是试图通过蛮力散列数百万个密码来猜测密码将会理解每个哈希计算的每一分之一秒.

    同样,解决方案很简单且众所周知:只需将密码重新散列几千次(或更多次)以减慢计算速度.甚至是标准化的方法,例如PBKDF2方法.或者,也可以使用特殊的专用密码散列函数,如bcryptscrypt,它通常带有salting和内置的可调迭代计数.

无论如何......所有这一切,实际上是计算你的密码哈希值,例如

hash = salt + bcrypt( sha1( md5( password + salt ) ) )
Run Code Online (Sandbox Code Playgroud)

即使有点复杂,也很好.此外,对于那个哈希链,几乎所有的时间都被bcrypt消耗,因为它是故意设计为慢速的三个哈希函数中唯一的一个.因此,在该哈希链之间应该没有明显的速度差异而只是bcrypt本身 - 并且,无论如何,您希望密码散列尽可能慢.