上周我读了很多关于密码哈希的文章,而Blowfish似乎是目前最好的哈希算法之一--但这不是这个问题的主题!
Blowfish只考虑输入密码中的前72个字符:
<?php
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$hash = password_hash($password, PASSWORD_BCRYPT);
var_dump($password);
$input = substr($password, 0, 72);
var_dump($input);
var_dump(password_verify($input, $hash));
?>
输出为:
string(119) "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)"
string(72) "Wow. This is a super secret and super, super long password. Let's add so"
bool(true)
关于“胡椒”密码有很多不同的意见。有些人说这是不必要的,因为您必须假设秘密的pepper-string也是已知/发布的,所以它不会增强哈希。我有一个单独的数据库服务器,所以很可能只有数据库被泄露,而不是恒定的Pepper。
在这种情况下(pepper没有泄露),您会使基于字典的攻击更加困难(如果这是不对的,请纠正我)。如果你的胡椒串也漏了:没那么糟--你还有盐,它就像没有胡椒的杂碎一样好保护。
因此,我认为,胡椒密码至少是一个不错的选择。
对于超过72个字符(和pepper)的密码,我的建议是:
<?php
$pepper = "foIwUVmkKGrGucNJMOkxkvcQ79iPNzP5OKlbIdGPCMTjJcDYnR";
// Generate Hash
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$password_peppered = hash_hmac('sha256', $password, $pepper);
$hash = password_hash($password_peppered, PASSWORD_BCRYPT);
// Check
$input = substr($password, 0, 72);
$input_peppered = hash_hmac('sha256', $input, $pepper);
var_dump(password_verify($input_peppered, $hash));
?>
这是基于以下问题:password_verify
returnfalse
。
比较安全的方法是什么?首先获取SHA-256哈希值(返回64个字符),还是只考虑密码的前72个字符?
这里的问题基本上是熵的问题。所以让我们从那里开始寻找:
每个字节的熵位数为:
代码的第一个问题是“pepper”哈希步骤输出十六进制字符(因为没有设置hash_hmac()
的第四个参数)。
因此,通过对pepper进行散列,可以有效地将密码可用的最大熵减少2倍(从576位到288位)。
但是,SHA256
首先只提供256
位熵。因此,有效地将可能的576位减少到256位。您的哈希步骤*立即*,根据非常明确的定义,丢失至少50%的可能熵在密码。
您可以通过切换到SHA512
来部分解决这个问题,在这里您只会将可用熵减少约12%。但这仍然是一个不小的差异。这12%将置换的数量减少了1.8e19
的一倍。这是一个很大的数字...这就是它减少它的因素...
潜在的问题是有三种类型的密码超过72个字符。这种风格系统对他们的影响将是非常不同的:
注意:从这里开始,我假设我们与使用SHA512
和原始输出(不是十六进制)的pepper系统进行比较。
>
高熵随机密码
这些是使用密码生成器的用户,这些生成器为密码生成大量的密钥。它们是随机的(生成的,而不是人类选择的),每个字符都有很高的熵。这些类型使用高字节(字符>127)和一些控制字符。
对于这个组,散列函数将显著地将它们的可用熵降低到bcrypt
。
让我再说一遍。对于使用高熵长密码的用户,您的解决方案可以显著降低其密码的强度。(对于72个字符的密码,损失62位熵,对于较长的密码,损失更多)
中熵随机密码
该组使用的密码包含公共符号,但没有高字节或控制字符。这些是你可键入的密码。
对于这个组,您将稍微解锁更多的熵(不是创建它,而是允许更多的熵适合bcrypt密码)。我所说的微微,是指微微。当您最大限度地耗尽SHA512的512位时,就会出现盈亏平衡。因此,峰值在78个字符。
让我再说一遍。对于这类密码,在熵耗尽之前只能存储额外的6个字符。
低熵非随机密码
这类熵计算在现实世界中并不重要。重要的是猜测熵。这是直接影响攻击者所能做的事情。这就是你想要最大化的。
虽然很少有研究去猜测熵,但我想指出一些观点。
连续随机猜中72个正确字符的几率极低。你更有可能赢得21次强力球彩票,而不是发生这种碰撞...这就是我们谈论的一个多大的数字。
我们举个例子。让我们引用《圣经》中的一句话(只是因为它是长文本的常见来源,而不是其他原因):
不可贪图邻舍的房子。你不可贪图邻舍的妻,或他的男仆,婢女,牛,驴,并你邻舍的一切物。
那是180个字符。第73个字符是第二个邻居的
中的G
。如果您猜到了那么多,那么您可能不会停在nei
,而是继续下面的部分(因为密码可能就是这样使用的)。因此,你的“哈希”并没有添加太多。
顺便说一句:我绝对不提倡使用圣经的引用。事实上,恰恰相反。
你不会真正帮助那些使用长密码先哈希的人。一些你绝对可以帮助的团体。一些你肯定会伤害的。
但最终,这些都不是过分重要的。我们处理的数字太高了。熵的差别不会太大。
专注于保护站点的其余部分。并在注册时在密码框中添加密码熵计,以指示密码强度(并指示如果密码过长,用户可能希望更改它)...
这至少是我的0.02美元(或者可能远远超过0.02美元)...
实际上没有研究将一个哈希函数添加到Bcrypt中。因此,充其量还不清楚向bcrypt中输入“pepped”散列是否会导致未知的漏洞(我们知道执行hash1(hash2($value))
可能会暴露碰撞抵抗和预映像攻击方面的重大漏洞)。
考虑到您已经在考虑存储一个秘密密钥(“Pepper”),为什么不以一种已经研究和理解的方式使用它呢?为什么不在存储哈希之前对其进行加密呢?
基本上,在对密码进行散列后,将整个散列输出输入到一个强加密算法中。然后存储加密的结果。
现在,SQL注入攻击不会泄漏任何有用的东西,因为它们没有密码。如果密钥泄露,攻击者的情况并不比使用普通哈希更好(这是可以证明的,pepper“pre-hash”不能提供的)。
注意:如果选择这样做,请使用库。对于PHP,我强烈推荐Zend Framework 2的Zend\crypt
包。这实际上是我目前唯一推荐的一个。它受到了强烈的审查,它为你做出了所有的决定(这是一件非常好的事情)...
类似于:
use Zend\Crypt\BlockCipher;
public function createHash($password) {
$hash = password_hash($password, PASSWORD_BCRYPT, ["cost"=>$this->cost]);
$blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
$blockCipher->setKey($this->key);
return $blockCipher->encrypt($hash);
}
public function verifyHash($password, $hash) {
$blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
$blockCipher->setKey($this->key);
$hash = $blockCipher->decrypt($hash);
return password_verify($password, $hash);
}
这是有益的,因为您使用的所有算法都是很好地理解和研究的(至少相对来说)。记住:
我的问题来自于如何用blowfish散列长密码(>72个字符) 我正在使用bcrypt(blowfish)对密码进行散列。因此,我从这个问题中发现https://security.stackexchange.com/questions/39849/does-bcrypt-have-a-maximal-password-length 它的字符限制为72。 所以,我开始考虑限制密码的最大长度,但在这些
问题内容: 我需要对密码进行哈希处理以存储在数据库中。如何用Java做到这一点? 我希望使用纯文本密码,添加随机盐,然后将盐和哈希密码存储在数据库中。 然后,当用户想要登录时,我可以使用其提交的密码,从其帐户信息中添加随机盐,对其进行哈希处理,然后查看其是否等同于其帐户信息所存储的哈希密码。 问题答案: 实际上,你可以使用Java运行时内置的工具来执行此操作。Java 6中的SunJCE支持PBK
我正在为拉拉维尔创建一个散列密码。现在有人告诉我使用Laravel哈希助手,但我似乎找不到它,或者我找错了方向。 如何创建laravel散列密码?在哪呢? 编辑:我知道代码是什么,但我不知道在哪里和如何使用它,所以它返回给我散列密码。如果得到散列密码,就可以手动将其插入数据库
我试图完全理解密码散列,以便能够向审计员解释它。 基于我对答案的搜索,我知道函数是的包装器。在阅读预定义常量的PHP手册时,我看到它使用作为默认整数值(基本上它使用算法来散列密码)。 让我困惑的是,变量如果省略,会生成一个随机salt,并且成本将设置为。如果我提供了更高的成本(例如:),由于我没有提供salt值,它还会生成随机salt吗?我在这里感到困惑的原因是,我没有忽略,而是提供了不同的成本。
控制器文件只是调用服务方法。 服务类别: 我想密码是在行中散列后验证的: 如何在散列和保存之前验证此密码? 如有任何帮助,不胜感激。提前谢了。
我正在处理一个pet项目,现在我想添加用户注册支持。经过一些研究,我决定在数据库中保存哈希密码和salt,而不是原始密码。然而,我不知道这些步骤是什么,顺序是什么。以下是我的假设: 注册 客户端向服务器发送用户名和密码(https) 服务器获取密码,生成随机salt Base64对盐进行编码 用stringify salt散列密码 Base64对密码进行编码 将密码和salt保存到数据库中 登录