Php 散列密码,从坏方法到现在最安全
我脑子里只有一个关于社区的简单问题。曾几何时,当我开始编程时,我使用md5对密码进行哈希处理,后来发现md5很容易被破解,我应该使用salt使其安全 我对md5没有信心,想使用sha1、sha256、SH512加密。但问题是现在我有加密形式的密码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("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.