Fre*_*mer 90 php security passwords hash blowfish
上周我读了很多关于密码哈希和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));
?>
Run Code Online (Sandbox Code Playgroud)
输出是:
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)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,只有前72个字符很重要.Twitter正在使用blowfish aka bcrypt存储他们的密码(https://shouldichangemypassword.com/twitter-hacked.php)并猜测:将您的Twitter密码更改为超过72个字符的长密码,您可以通过以下方式登录您的帐户:只输入前72个字符.
关于"胡椒"密码有很多不同的意见.有些人说这是不必要的,因为你必须假设秘密胡椒串也是已知/已发布的,因此它不会增强散列.我有一个单独的数据库服务器,所以很可能只有数据库被泄露而不是常数胡椒.
在这种情况下(辣椒没有泄漏)你根据字典进行攻击更加困难(如果这不对,请纠正我).如果你的辣椒串也泄漏了:没那么糟糕 - 你仍然有盐,它就像没有辣椒的哈希一样受到保护.
因此,我认为密码密码至少是不错的选择.
我建议为超过72个字符(和胡椒)的密码获取Blowfish哈希是:
<?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));
?>
Run Code Online (Sandbox Code Playgroud)
这是基于这个问题:password_verify返回false.
什么是更安全的方式?首先获取SHA-256哈希(返回64个字符)或仅考虑密码的前72个字符?
编辑1:这个问题只针对blowfish/bcrypt的PHP集成.感谢您的评论!
irc*_*ell 132
这里的问题基本上是熵问题.那么让我们开始寻找:
每字节熵的位数是:
所以,我们如何行动取决于我们期望的角色类型.
您的代码的第一个问题是,您的"胡椒"哈希步骤输出十六进制字符(因为hash_hmac()未设置第四个参数).
因此,通过对胡椒进行散列,您可以有效地将密码可用的最大熵减少2倍(从576到288个可能的位).
但是,首先sha256只提供256一些熵.所以你有效地将可能的576位削减到256位.您的哈希步骤*立即*,通过非常定义丢失
密码中至少 50%的可能熵.
您可以通过切换到部分解决此问题SHA512,您只需将可用熵减少约12%.但这仍然是一个无关紧要的差异.12%将排列数量减少了一倍1.8e19.这是一个很大的数字......这是它减少它的因素 ......
根本问题是有超过72个字符的三种类型的密码.这种风格系统对它们的影响将大不相同:
注意:从现在开始我假设我们正在与使用SHA512原始输出(不是十六进制)的胡椒系统进行比较.
高熵随机密码
这些是您的用户使用密码生成器生成密码的大密钥.它们是随机的(生成的,而不是人类选择的),并且每个字符具有高熵.这些类型使用高字节(字符> 127)和一些控制字符.
对于这个组,您的散列函数将显着减少其可用的熵bcrypt.
让我再说一遍.对于使用高熵,长密码的用户,您的解决方案会以可测量的数量显着降低密码强度.(对于72个字符的密码,丢失了62位熵,对于更长的密码,则丢失了更多的熵)
中等熵随机密码
该组使用包含公共符号的密码,但没有高字节或控制字符.这些是你的典型密码.
对于这个组,你将略微解锁更多的熵(不创建它,但允许更多的熵适合bcrypt密码).当我略微说,我的意思是略.当您最大化SHA512所具有的512位时,会发生收支平衡.因此,峰值为78个字符.
让我再说一遍.对于此类密码,在熵耗尽之前,您只能存储6个字符.
低熵非随机密码
这是使用可能不是随机生成的字母数字字符的组.像圣经引用或类似的东西.这些短语每个字符具有大约2.3位的熵.
对于此组,您可以通过散列显着解锁更多熵(不创建它,但允许更多适合bcrypt密码输入).在你用完熵之前,盈亏平衡点大约是223个字符.
让我们再说一遍.对于此类密码,预先散列肯定会显着提高安全性.
这些类型的熵计算在现实世界中并不重要.重要的是猜测熵.这就是攻击者可以做的直接影响.这就是你想要最大化的东西.
虽然很少有研究猜测熵,但我想指出一些观点.
连续猜测连续72个正确字符的可能性非常低.你更有可能赢得强力球彩票21次,而不是发生碰撞...这就是我们谈论的数字有多大.
但我们可能不会在统计上发现它.在短语的情况下,前72个字符相同的可能性比随机密码高很多.但它仍然很低(你更有可能赢得强力球彩票5次,基于每个字符2.3位).
实际上,它并不重要.有人猜测前72个字符的可能性是正确的,后者会产生显着差异,因此不值得担心.为什么?
好吧,假设你说的是一句话.如果这个人能够得到正确的前72个字符,那么他们要么真的很幸运(不太可能),要么就是一个常见的短语.如果它是一个常见的短语,唯一的变量就是它需要多长时间.
我们来举个例子吧.让我们从圣经中引用一句话(因为它是长文本的常见来源,不是出于任何其他原因):
你不应该贪图你邻居的房子.你不应该贪图你邻居的妻子,他的男仆或女仆,他的牛或驴,或属于你邻居的任何东西.
这是180个字符.第73个字符是g第二个字符neighbor's.如果你猜到那么多,你可能不会停下来nei,但继续阅读其余部分(因为密码可能会被使用).因此,你的"哈希"没有增加多少.
顺便说一句:我绝对不提倡使用圣经引用.事实上,恰恰相反.
你不是真的会帮助那些通过哈希首先使用长密码的人.有些团体你肯定可以提供帮助.有些你肯定会受伤.
但最终,这些都不是太重要.我们正在处理的数字只是WAY太高.熵的差异不会太大.
你最好离开bcrypt.你试图阻止的攻击将会发生,你更有可能搞砸哈希(字面意思是,你已经完成了,并且你不是第一个或最后一个犯错误).
专注于保护网站的其余部分.并在注册时在密码框中添加密码熵计,以指示密码强度(并指示密码是否过长,用户可能希望更改密码)...
这至少是0.02美元(或者可能超过0.02美元)......
实际上没有研究将一个哈希函数输入到bcrypt中.因此,最好不清楚的是,如果向bcrypt提供"胡椒"散列将导致未知漏洞(我们知道这样做hash1(hash2($value))可能会暴露围绕碰撞阻力和前映像攻击的重大漏洞).
考虑到你已经在考虑存储一个密钥("胡椒"),为什么不以一种经过充分研究和理解的方式使用它?为什么不在存储之前加密哈希?
基本上,在对密码进行哈希处理后,将整个哈希输出提供给强加密算法.然后存储加密结果.
现在,SQL注入攻击不会泄漏任何有用的东西,因为它们没有密码密钥.如果密钥被泄露,攻击者并没有比使用普通哈希(这是可证明的,胡椒"预哈希"不提供的东西)更好.
注意:如果您选择这样做,请使用库.对于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);
}
Run Code Online (Sandbox Code Playgroud)
这是有益的,因为你以很好理解和充分研究的方式使用所有算法(相对至少).记得:
任何人,从最无能的业余爱好者到最好的密码学家,都可以创建一个他自己无法破解的算法.
佩戴密码肯定是件好事,但让我们明白为什么.
首先,我们应该回答问题,确切的胡椒有助于.胡椒只保护密码,只要它保密,所以如果攻击者可以访问服务器本身,那就没用了.一个更容易的攻击是SQL注入,它允许对数据库的读访问(对我们的哈希值),我准备了一个SQL注入的演示,以显示它是多么容易(点击下一个箭头来准备输入).
然后胡椒实际上有什么帮助?只要辣椒保密,它就可以保护弱密码免受字典攻击.密码1234将变成类似的东西1234-p*deDIUZeRweretWy+.O.这个密码不仅更长,它还包含特殊字符,永远不会成为任何字典的一部分.
现在我们可以估计用户将使用哪些密码,可能会有更多用户输入弱密码,因为密码介于64-72个字符之间的用户(实际上这将是非常罕见的).
另一点是暴力迫使的范围.sha256散列函数将返回256位输出或1.2E77组合,这对于暴力强制来说太多了,即使对于GPU来说也是如此(如果我正确计算,2013 年在GPU上需要大约2E61年).所以我们不应该使用辣椒真正的劣势.因为哈希值不是系统的,所以无法加速使用常见模式的强制执行.
PS据我所知,72字符限制特定于BCrypt本身的算法.我找到的最佳答案是这个.
PPS我认为您的示例有缺陷,您无法生成具有完整密码长度的哈希值,并使用截断的密码验证它.您可能打算以相同的方式应用胡椒来生成散列和验证散列.