上周,我读了很多关于密码散列和河豚的文章似乎是(之一),现在最好的哈希算法 - 但这不是这个问题的话题!
72个字符的限制
河豚只考虑在输入密码的前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)
只是正如你所看到的第一个72个字符关系。 Twitter正在使用河豚又名bcrypt来存储自己的密码( https://shouldichangemypassword.com/twitter-hacked.php )和猜测:有超过72个字符改变你的Twitter密码的长密码,你可以通过登录到您的帐户只进入第一72个字符。
Blowfish和辣椒
有关于“尖刻”的密码了很多不同的意见。 有人说这是不必要的,因为你必须假设秘密辣椒串又称/发表,因此不会提高哈希值。 我有一个单独的数据库服务器,因此它很可能只有数据库被泄露,而不是恒定的辣椒。
在这种情况下(辣椒不被泄露),你让基于字典更加困难(纠正我,如果这是不对的)攻击。 如果您的辣椒串也被泄露:没那么糟糕 - 你仍然有盐,它的良好保护,没有辣椒的哈希值。
所以我觉得尖刻的密码至少不坏的选择。
建议
我的建议得到了超过72个字符(和胡椒)密码的河豚哈希:
<?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
返回false
。
问题
什么是安全的方式? 得到一个SHA-256哈希第一(返回64个字符)或只考虑密码的第一个72个字符?
优点
- 用户无法通过输入只是第72个字符登录
- 您可以添加辣椒不超过字符限制
- hash_hmac的输出可能会比密码本身更熵
- 密码是由两个不同的功能散列
缺点
编辑1:这个问题不仅不会忽略河豚/ bcrypt的PHP集成。 感谢对评论!
这里的问题基本上是熵的问题。 因此,让我们开始寻找有:
熵每字
每字节熵比特数是:
- 十六进制字符
- 字母数字
- “common”标志
- 全字节
那么,我们如何行动取决于我们期待什么类型的字符。
第一个问题
与您的代码的第一个问题是,你的“辣椒”散列步骤输出十六进制字符(因为第四个参数hash_hmac()
未设置)。
因此,通过散列你胡椒,你用有效的2(从576到288 可能位)的因素切割可用密码的最大熵。
第二个问题
然而, sha256
只提供256
放在首位熵位。 所以你有效地切断可能的576位下降到256位。 你的哈希步* *立即由本身的定义失去的密码可能的熵的至少 50%。
你可以通过切换到部分地解决了这个SHA512
,在这里你只约12%减少可用的熵。 但是,这仍然是一个不可忽略的差别。 这12%的因数降低了排列的数目1.8e19
。 这是一个大数目......就是这样通过降低它的因素 ...
根本的问题
根本的问题是,有三种类型超过72个字符的密码。 这种风格系统对他们的影响会有很大的不同:
注意:从这里开始了我假设我们要比较于使用胡椒系统SHA512
与原始输出(不是十六进制)。
高熵的随机密码
这些都是使用产生什么样量为密码按键宽大密码生成你的用户。 他们是随机的(产生的,没有人选择),并且每个字高熵。 这些类型均使用高字节(字符> 127)和一些控制字符。
对于这一组,你的散列函数会显著减少其可用熵到bcrypt
。
让我再说一遍。 对于谁是使用高熵,长密码的用户,您的解决方案显著降低可测量的量的密码强度。 (熵的62个比特丢失了72个字符的密码,多用于较长的密码)
中熵的随机密码
该组被使用含有常用符号密码,但没有高字节或控制字符。 这些都是你的密码键式。
对于这一组,你要稍微解开更多的熵(不创建它,而是让更多的熵融入bcrypt密码)。 当我说咯,我稍微意思。 当您最大程度的发挥512位是SHA512具有收支平衡发生。 因此,峰值是在78个字符。
让我再说一遍。 对于这类密码,您可以在用完熵的前只能存储一个额外的6个字符。
低熵非随机密码
这是谁正在使用的可能不是随机生成的字母数字字符组。 像一本圣经报价或此类。 这些短语有每个字符的熵的大约2.3位。
对于这个组,可以显著通过散列解开更多的熵(不创建它,而是让更多的融入bcrypt密码输入)。 盈亏平衡大约是223个字符,你用完了熵之前。
让我们再说一遍。 对于这类密码,预哈希绝对显著提高了安全性。
回到现实世界
这些类型的熵的计算并不真正的问题多,在现实世界中。 重要的是猜测熵。 这就是直接的影响是什么攻击者可以做。 这就是你想要什么最大化。
虽然有这么不见了成猜测熵的研究很少,也有一些,我想指出的点。
的随机猜测在一排72个正确字符的可能性非常低。 你就更有可能赢得强力球彩票的21倍,比有这种碰撞......这是多大我们谈论了许多。
但是,我们可能无法在统计上它绊倒。 在短语的情况下,第一72个字符是相同的机会比一个随机密码较高一大堆。 但它仍然是平凡低(你更有可能赢得强力球彩票的5倍,基于每个字符2.3位)。
几乎
实际上,它并不真正的问题。 有人猜测第72个字符正确,后者者作出显著差异的机会是如此之低,这是不值得担心。 为什么?
好吧,让我们说你正在做的短语。 如果人能拿到第72个字符的权利,他们要么真的很幸运(不太可能),或者这是一个常见的词组。 如果它是一个常见的词组,唯一的变量是多久才能做到这一点。
让我们看一个例子。 让我们引自圣经(只是因为它是长文本的一个共同的来源,而不是任何其他原因):
你不可贪图你的邻居的房子。 你不可贪恋人的妻子,他的仆人仆婢,他的牛,驴,或任何属于你的邻居。
这是180个字符。 第73字符是g
第二neighbor's
。 如果你猜是多少,你可能不会在停止nei
,但与诗的其余部分继续(因为这是密码会如何被使用)。 因此,你的“哈希”没有增加多少。
BTW:我绝对没有使用的圣经报价主张。 事实上,正好相反。
结论
你不是真的要帮助的人多谁首先散列使用长密码。 一些团体,你一定能帮助。 有些你绝对可以伤害。
但最终,这一切没有过于显著。 我们正在处理的数字只是太高 。 在熵的差异不会太大。
你马上去bcrypt,因为它是更好的。 你很可能会搞砸了散列(从字面上看,你做到了已经,而且你不是第一个,或最后,以犯类似的错误)比你试图阻止事情发生了攻击。
专注于固定网站的其余部分。 和密码熵计添加到密码框上登记,表示密码强度(并注明如果密码过长,用户可能希望改变它)...
这是我的$ 0.02,至少(或可能的方式超过$ 0.02)...
至于使用一个“秘密”辣椒:
从字面上有没有研究到喂养一个散列函数分为bcrypt。 因此,目前还不清楚,在最好的,如果喂“胡椒”散列成bcrypt都不会造成未知的漏洞(我们知道这样hash1(hash2($value))
可以暴露围绕抗碰撞性和原像攻击显著漏洞)。
考虑到你已经在考虑保存密钥(以下简称“胡椒”),为什么要在这个井的研究和理解的方式不使用它呢? 为什么不早于存储时进行加密哈希?
基本上,你哈希密码后,养活整个哈希输出成一个强大的加密算法。 然后存储加密的结果。
现在,一个SQL注入攻击不会泄漏任何有用的东西,因为他们没有密钥。 而如果密钥泄漏,攻击者没有关闭,如果你使用普通的哈希优于(这是可证明,一些与花椒“预哈希”不提供)。
注意:如果你选择这样做,使用图书馆。 对于PHP,我强烈建议Zend框架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);
}
它是有益的,因为你正在使用的所有的算法是很好的理解并很好的研究方法(比较至少)。 记得:
任何人,从最无能爱好者最好的译电员,可以创建一种算法,他本人不能打破。
尖刻的密码肯定是做的,但让我们来看看为什么一件好事。
首先,我们应该回答这个问题什么时候辣椒帮助。 胡椒不仅保护了密码,只要它保持秘密,所以,如果攻击者能够访问到服务器本身,它是没有用的。 一个更容易的攻击虽然是SQL注入,允许读取访问数据库(我们的哈希值),我准备了一个SQL注入的演示来显示它多么容易(点击旁边的箭头获得准备输入)。
那么,什么是辣椒实际的帮助? 只要保持辣椒秘密,它保护从字典攻击弱密码。 密码1234
,然后会成为像1234-p*deDIUZeRweretWy+.O
。 这个密码是不仅要长得多,它也包含特殊字符,并且将永远不会有任何字典的一部分。
现在,我们可以估算一下我们的口令用户会使用,可能更多的用户将进入弱密码,因为有用户使用64-72个字符(实际上这将是非常罕见的)之间的密码。
另一点是暴力破解的范围内。 该SHA256哈希函数将返回256位输出或1.2E77组合,这方面太多的暴力破解,即使是GPU的(如果我计算正确,这将需要大约2E61年在GPU在2013年)。 所以,我们没有得到应用辣椒一个真正的缺点。 由于哈希值是不是系统性的,你不能加快与普通模式暴力破解。
PS据我所知,72个字符的限制是特定于BCrypt本身的算法。 最好的答案,我发现是这个 。
PPS我觉得你的例子是有缺陷的,你不能生成完整的密码长度的哈希值,并用截短一个验证。 你可能意味着应用辣椒做同样的方式生成散列和散列的验证。
Bcrypt使用基于昂贵的Blowfish键设置算法的算法。
所推荐的56字节密码限制(包括空终止字节),用于bcrypt涉及的Blowfish密钥的448位限制。 超出限额的任何字节不完全混合所产生的哈希值。 因此在bcrypt密码的72字节的绝对限制是不太相关的,当你考虑这些字节的结果散列的实际效果。
如果你认为你的用户通常会选择的密码长度超过55个字节,还记得你总是可以提高密码的伸展而不是回合,以增加其在密码表违约的情况下,安全性(尽管这已被大量使用添加额外的比较字符)。 如果用户的访问权限是关键,以至于用户通常需要一个大规模长密码,则密码到期也应该是短期,如2周。 这意味着密码很可能要少得多,而黑客投资其资源在击败参与测试每个试验密码,看它是否会产生一个匹配的散列工作因素被保持有效。
当然,在不违反被密码表的情况下,我们应该只允许黑客,顶多十次猜测用户的55字节的密码,锁定用户帐户之前;)
如果你决定预哈希密码大于55个字节长,那么你应该使用SHA-384,因为它没有去超过限制的最大输出。