这个哈希算法在安全方面有什么优势吗?

4

有什么优势呢?

sha1(sha1(sha1($password. $salt)));

基本上,拥有多个 SHA1 与只有一个 SHA1 相比

sha1($password. $salt);

如果您的$salt足够强大、更长且是一组随机字符混合而成,则后者就足以满足需求了。基本上,只有在某人使用您的salt编译出彩虹表的情况下,后者才会受到攻击,这种可能性几乎为零,如果您的$ salt足够强大,例如12@!(E&HD&@#HE!_)UDJNuyhdsbq897cuddaadn*&BD#NXUHSD8uyahs…在我看来,使用多个sha1只是更安全一点。 - Stoic
谢谢。我正在使用强盐。 - Jason
相关问题及其良好的信息和讨论:很多哈希迭代,每次都添加盐? - ircmaxell
4个回答

9
请勿尝试通过对哈希值进行“特殊”处理来使密码哈希更加安全。首先,sha1(sha1(sha1($ input)))的唯一副作用是在每次迭代中增加碰撞的可能性*。增加碰撞的可能性是非常糟糕的事情。与其自己尝试加密学,为什么不信任由该领域的实际专家制作的库呢?使用{{link1:Portable PHP密码哈希框架}}。PHPass实际上使用了bcrypt,这是一种旨在防止彩虹表、字典和暴力攻击的算法。您可以使用多个轮次初始化它:轮次越高,计算哈希所需的时间就越长。这样,如果处理能力增加,您可以创建更强的哈希。

*第一次调用sha1()时,需要无限的输入并创建2160个输出之一。第二次迭代需要2160个输入,并创建一个输出,其中x <= 2160。第三次迭代需要x个输入,并创建一个输出,其中y <= x <= 2160

为什么每次调用sha1()都会减少可能的输出数量?因为sha1()背后的算法并不是为了进行哈希的一对一匹配而设计的。理论上,如果您要哈希每个可能的哈希值,则必定会发生碰撞。


phpAss本身使用多次迭代进行哈希(只需查看第一个方法即可),这是一种良好的安全实践。 - Alix Axel
@Alex Axel:在便携模式下,确实是这样的。但是,它总是重新计算前一个哈希值与密码连接后的哈希值(sha1($hash . $password)),使得可能的输入变为无限,因此不会增加碰撞的机会...通常,$password 是唯一的无限输入源,除非您使用每个哈希值的 $salt - Andrew Moore
@Andrew Moore:您的论点存在谬误,bcrypt与sha1具有相似的碰撞机率 - 两者都会被多次重新散列。 - Alix Axel
1
@Alix:不行。调用sha1(... sha1($ f00))会产生越来越多的碰撞。为了看清楚,让我们把它命名为A(B(C($ foo)))。现在,我们知道C会有碰撞,因为无限大> 2 ^ 256。因此,所有C的碰撞自动成为AB的碰撞,因为输入未被修改。对于BA也是如此。因此,总碰撞比仅针对C要多得多。但是,如果您执行A(B(C($ foo)。$ Foo)。$ Foo),它将与C具有完全相同数量的碰撞... - ircmaxell
@Alix Axel: bcrypt实际上并不会对密码进行任何迭代转换。bcrypt重复对一个初始化向量进行转换多次,以便使用结果向量创建哈希。简单来说,它将“盐”(IV)多次转换,直到它在加密方面足够安全,从而可以生成哈希值。要将输入与bcrypt哈希进行比较,您需要存储的哈希值以提取原始IV(存储在哈希中,每个哈希都是唯一的),让bcrypt再次转换向量,哈希原始输入,并比较两个结果哈希。 - Andrew Moore
评论编辑:实际上,在修订了bcrypt规范之后,它使用IV和输入来生成子密钥...不过这并不影响它发生碰撞的机会。 - Andrew Moore

2
是的,这被称为密钥强化(但通常会进行数千次),在每次迭代中都应该附加盐以获得更好的熵值:
$hash = sha1($password . $salt);

for ($i = 1; $i <= 65000; ++$i)
{
    $hash = sha1($hash . $salt);
}

另外,阅读这篇精彩的博客文章,或者至少阅读这段简短的引用:
你能优化密码散列函数的速度越快,你的密码散列函数就越弱。MD5和SHA1甚至包括DES在内的传统分块密码,都被设计成快速计算。MD5、SHA1和DES都是弱密码散列函数。在现代CPU上,像DES和MD5这样的原始加密模块可以进行位切片、向量化和并行化处理,以使密码搜索变得极快。游戏结束的FPGA实现只需要几百美元。使用原始散列函数来验证密码的方式与使用未加盐散列函数一样幼稚。现在的最新技术是什么呢?首先,你所用的操作系统已经提供了一个“优化”的密码方案,以使计算变得昂贵。其中最著名的是PHK的FreeBSD MD5方案。PHK的方案与你准备在社交购物车2.0应用程序中使用的方案之间的区别很简单。你只打算在一个盐和一个密码上运行MD5并存储散列值。PHK对MD5进行了数千次迭代处理。这称为“拉伸”。

始终尽可能多地重新引入每个哈希周期中的信息。我建议在内部的sha1调用中也添加密码。有关更多信息,请参见此答案。还可以查看PBKDF2标准以进行密钥拉伸。 - ircmaxell
除非在每个哈希生成时更改$salt,否则不要使用sha1($hash . $salt)。如果不这样做,由于与我的答案中所述的相同原因,会增加发生碰撞的几率。 - Andrew Moore

1
简短的回答是不行。当你链接两个哈希算法时,你所做的只是创建另一个具有未知属性(从安全角度来看)的哈希算法。使用盐(或者更好的是HMAC)。

0
通过哈希处理的次数越多,哈希所需的时间就越长,攻击者每天可以尝试的次数就越少。如果哈希一次需要10ms,并且哈希十次需要100ms,则攻击者每分钟可以尝试使用哈希一次的方式尝试6000个密码,并且使用哈希十次的方式只能尝试每分钟600个密码。当然,在Web应用程序中,尝试以每分钟6000或600次的速度进行暴力破解实际上是一种拒绝服务攻击(DOS攻击)。加密哈希倾向于花费一定的时间进行处理,通常也会进行多次哈希。
你应该使用sha512而不是sha1,可以使用hash('sha512',$stringtobehashed); 进行操作,sha512的哈希时间大约比sha1长5倍。

这是在假设它在单核心且没有并行处理的情况下运行。理论上它可以在多个核心上运行(12核心系统很常见,GPU拥有更多)。更不用说使用流水线技术可以同时运行多个哈希,因此实际数字可能远高于每分钟6k个密码(如果一块好的硬件不能达到每分钟100k或更高速度,我会感到惊讶)... - ircmaxell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接