openssl_digest vs hash vs hash_hmac?SALT和HMAC之间的区别?

Thi*_*key 15 php security passwords hash

我想使用SHA512来存储密码.要做到这一点,其中openssl_digest,hashhash_hmac我应该使用,为什么?


SALTHMAC?有什么区别?


我刚刚读到HMAC是建立在哈希函数之上的.

所以SHA512+SALT+HMAC真的有必要SHA512+SALT或者SHA512+HMAC

irc*_*ell 58

所以,首先,让我们清楚一件事.openssl_digest()=== hash().它只是另一个不同名称的功能,完全相同.它计算输入的加密哈希值.

那么,现在我们有了一个问题:存储密码时哪个更好:hash或者hash_hmac

简答:

也不

答案很长:

事实证明,彩虹表已经死了.只是使用hash($password . $salt)甚至hash_hmac($password, $salt)不够密码存储.期.如果您这样做,请立即停止.

原因很简单:计算机(或GPU)上的计算时间非常便宜.这是如此便宜,以至于蛮力的密码列表足够便宜,你需要担心它.请记住,哈希函数设计得很快.不贵啊...

但是,事实证明,有一种方法可以使这些快速哈希函数更加昂贵.事实上,它非常简单:迭代.

现在,我知道你在想什么.你将只是循环哈希:

function hash_password($password, $salt) {
    $hash = hash("sha512", $password . $salt);
    for ($i = 0; $i < 1000; $i++) {
        $hash = hash("sha512", $hash);
    }
}
Run Code Online (Sandbox Code Playgroud)

当然这很好,对吧?不.正如Hashing和Encryption之间的基本差异所解释的那样,这不是一个好主意.那么为什么不再重新输入密码和盐呢?

function hash_password($password, $salt) {
    $hash = hash("md5", $salt . $password);
    for ($i = 0; $i < 1000; $i++) {
        $hash = hash("md5", $hash . $password);
    }
}
Run Code Online (Sandbox Code Playgroud)

事实上,这正是PHPASS使用的(略微调整,但这是基本算法)...

所以现在1次调用hash_password执行1000个哈希循环.

但我们可以改进吗?

好吧,事实证明,我们可以.下一个合乎逻辑的做法是看看我们是否可以在相同的时间内获得更多的哈希循环.这就是它的hash_hmac()用武之地.事实证明,HMAC每次调用时都会使用2个哈希周期.而且因为它全部是C,所以它只需要花费大约1.5倍的时间hash()来完成一轮.

因此,这意味着,如果我们更换hashhash_hmac,我们可以立即看到的工作量增加了33%,在规定时间内正在做.所以现在我们在这里:

function hash_password($password, $salt) {
    $hash = hash_hmac("md5", $salt, $password);
    for ($i = 0; $i < 1000; $i++) {
        $hash = hash_hmac("md5", $hash, $password);
    }
}
Run Code Online (Sandbox Code Playgroud)

这实际上是PBKDF2的基本内循环.

但我们可以变得更好吗?

是的,再次,我们可以变得更好.如果我们仔细观察,我们可以看到 - 除了密码和盐 - 所有上述算法都使用非常少量的内存.在sha512的情况下,它们将使用128到256字节(缓冲区和状态)的顺序来散列密码.由于内存使用量非常小,因此在GPU中并排运行大量内存非常简单.如果我们只能增加内存使用量......

好吧,事实证明,我们可以简单地使用bcrypt,这是一种自适应散列算法.它的优点是它使用比上述算法更多的内存(大约4到5kb).因此,对并行化更具抵抗力.并且由于它的计算成本很高,所以它对强制执行是不利的.

幸运的是,它适用于PHP:

crypt($password, '$2y$07$usesomesillystringforsalt$')
Run Code Online (Sandbox Code Playgroud)

需要注意的是crypt()使用了很多算法,但$2y$$2a$算法bcrypt.

但我们能改进吗?

的种类.有一种叫做scrypt的相对较新的算法.它比bcrypt更好,因为它的计算成本非常高,但是使用了更多的内存(大约20mb到40mb来散列单个密码).因此,对并行化更具抵抗力......

不幸的是,scryptPHP 尚未提供(我正在努力改变它).在那之前,使用bcrypt......

边注

LinkedIn,LastFM,Hotmail,Gawker等最近的经验教训之后,很明显很多人都做错了.不要做错,使用带有审查算法的库.使用CRYPT_BLOWFISH(bcrypt),使用PHPASS,使用PasswordLib.但是不要仅仅因为你不想依赖而发明自己的......这只是疏忽.

更多阅读:


Dar*_*ust 7

HMAC使用哈希算法(如SHA512)的特定方法.它用于签署消息,然后您可以验证消息是否来自特定签名者并且未被更改.所以这不是你想要的.

用于比特"随机性"的添加到应该被加密或散列文本.关键是,即使您多次加密相同的文本,您也会得到不同的结果.这使得进行一些攻击变得更加困难.这就是你想要的:SHA512(salt+password).

对于存储密码,我能想象的最安全的方式是:

(免责声明:我对加密技术不是很熟悉,可能有更好的解决方案)

  • 客户端(JavaScript代码?)会生成一个salt值.
  • 然后,客户端将salt和密码组合在一起,并通过散列算法运行结果.
  • 然后,客户端将salt和hash值都发送到存储它的服务器(最好是在不同的位置).

要验证密码,您需要执行以下操作:

  • 将盐传递给客户.
  • 客户端将salt和输入的密码组合在一起,通过哈希算法运行它.
  • 客户端将哈希值发送到服务器.
  • 服务器将哈希值与存储的哈希值进行比较.如果匹配,则密码相同.

当然,你可以用明文传输密码并在服务器上进行整个salting和散列,但这会大大削弱你的解决方案.您绝不应以明文形式传输密码.

但是"将盐传递给客户"部分可能是个问题.我可以想象解决这个问题的一种方法是以某种方式从用户名中获取salt(最简单的方法:简单地做lowercase(username) + password),但问题在于盐是可预测的,从而稍微削弱了你的解决方案.然而,它仍然方式比发射"原始"哈希更好,你甚至不会需要存储的盐,你可以从用户名,每次得到它.如果您的密码数据库被盗,它仍然可以通过这种"用户名腌制"方法抵御彩虹表攻击.

问题是仍然可能发生中间人攻击.如果攻击者拦截用户名和哈希,则它具有所有相关的信息,并且与发送明文密码没有任何不同.因此,您可能希望使用SSL(HTTPS)保护连接.