恐怕要问这个老问题了,我会惹起西红柿来,但就这样。

读完现有哈希函数编写自己的密码哈希后,一遍又一遍是危险的我还是不明白逻辑。以下是一些示例:


md5(md5(salt) + bcrypt(password))
scrypt(bcrypt(password + salt))
sha1(md5(scrypt(password + md5(salt))))

反对这些的典型论据如下:


你不是密码学家!您不知道这些哈希是否更安全。将其交给知道自己在做什么的专家。这些没有增加额外的安全性。


当然,它们并不能改善哈希函数(即,使其更难以反转或发现冲突等),但可以肯定的是它们不会使它变得更糟吗?如果他们这样做了,那么黑客将能够在他们认为合适的情况下将标准的哈希密码重新哈希化为这些古怪的哈希值并削弱哈希值?我不买它。

第二个参数: >

同意。基本上,这是首先不要将密码存储为纯文本的动机。但是,如果我对第一个批评的回应仍然成立,那么这些古怪的哈希仍然可以用作安全哈希,而且我们的系统不会像使用标准哈希那样破坏Kerckoffs的原理。


当然,如果攻击者拥有源代码,则您的系统应该是安全的,但是攻击者很可能无法访问您的源代码,并且很可能无法猜测您古怪的哈希,从而无法进行任何暴力破解。
(这是我问这个问题的真正动力)BCrypt被认为是安全的,对CPU和GPU(大型)来说很难,但是在使用专用硬件时可以非常快。据说SCrypt很难在CPU,GPU和当前可用的专业工具上进行暴力破解,但是由于缺乏公开性,因此更新较新,并且不像BCrypt受到密码界的信任。但是哈希BCrypt(SCrypt(password + salt))不能兼得两者吗?

我很欣赏大多数对这些自制哈希的怨言背后的热情/愤怒,这是由于普通程序员对如何编写好的哈希值缺乏了解,以及担心会鼓励这种古怪的哈希运算将不可避免地以弱无用的哈希值进入生产代码。但是,如果古怪的哈希值是由可靠且可靠的哈希值精心构造而成的,那么在安全方面获得的收益就不是十分有价值和真实吗?
一堆很好的答案,谢谢。在我的假设中,我似乎忽略了的是,尽管结合使用哈希不能使破解原始密码更容易,因此也不能破解组成哈希,但是至少在原则上,两个或更多个安全哈希的结合可能较弱比其内部的任何一种哈希都高,这是由于它们之间未经研究且复杂的相互作用。意味着有可能找到一些经过古怪的哈希的字符串,而不必破坏组成哈希的哈希。

评论

如果您的目标只是在没有访问源代码的情况下防止攻击者攻击,那么使用Pepper(基本上是与密码一起哈希的硬编码秘密值)就足够了,并且比创建自己的密码更不易出错哈希函数。

为什么不增加睡眠(15000);每个哈希之后?确定的好处是未知的,但肯定不会降低它的安全性:)

#1 楼

您需要问这个问题的事实本身就是答案–您不知道堆叠这些原语有什么问题,因此可能无法知道其中有什么好处或缺点。在您提供的每个示例中:

md5(md5(salt) + bcrypt(password))

我可以在这里看到一些问题。首先是您要对盐进行MD5处理。这有什么好处?没有。它增加了复杂性,并且盐仅是为了防止密码冲突和预计算(例如彩虹表)攻击而具有唯一性。在这里使用MD5没有任何意义,并且实际上可能会削弱该方案,因为MD5已知有一些小冲突。因此,在此处引入MD5的可能性很小,这意味着两种独特的盐会产生相同的MD5哈希值,从而导致有效地复制盐。不好。

接下来,您在密码上使用bcrypt。好。好吧,大多数bcrypt实现在内部都需要加盐,因此从技术上讲这已经无效。假设您知道这一点,而您的意思是说bcrypt(md5(salt), password)。这部分仍然属于我上面描述的弱点,但是它并不破旧-删除MD5,这是bcrypt的标准用法。你为什么做这个?目的是什么?它带来什么好处?据我所知,根本没有好处。在不利方面,它增加了更多的复杂性。由于大多数bcrypt实现都使用a$rounds$salt$hash表示法,因此您将不得不编写代码以对其进行解析,以便可以提取哈希部分并将其余部分分开存储。您还需要一个MD5实现,这是不必要的。自定义解析代码和MD5实现,以及一些粘合代码将它们粘合在一起。为了实现零收益,并在盐处理方面存在潜在的漏洞。

下一个:

scrypt(bcrypt(password + salt))

这还不错,但是同样,您需要一些代码将bcrypt的结果分别解析为哈希和盐/舍入计数。在这种情况下,我猜想会有一点好处,因为bcrypt和scrypt可以以不同的方式工作以达到大致相同的目标,这会使资金充裕的攻击者构建定制ASIC来破坏您的ASIC更加困难。方案。但这真的有必要吗?您是否真的要碰到一个民族国家会花费数百万美元来破坏哈希的情况?而且,如果出现这种情况,那么是否真的要花费几百万美元才能使攻击者的筹码数量增加一倍呢?

结合使用bcrypt和scrypt这样的另一个潜在问题是:很少研究两者如何相互作用。因此,我们不知道是否有任何奇怪的情况可能导致问题。举一个更明显的例子,一个时间垫。我们为某些消息c=m^k和一些同样长的完全随机密钥m计算k,从而获得了完美的安全性。因此,让我们做两次,以提高安全性!这给了我们c=m^k^k ...哦,等等,这给了我们m。因此,由于我们没有花时间正确地了解系统内部的工作原理,因此最终导致了一个真正的安全漏洞。显然,对于KDF来说,它要复杂得多,但应用相同的原理。

最后:

sha1(md5(scrypt(password + md5(salt))))

再次,我们遇到了MD5版本的盐问题。 MD5将SHA1哈希值也吸引了我。如果您已经在使用像scrypt这样的慢速KDF,可能会有什么好处?与计算密码的scrypt摘要所花费的数百毫秒相比,计算这些哈希所花费的几毫微秒差。您正在为绝对不相关的“安全性”层添加复杂性,这总是一件坏事。您编写的每一行代码都是潜在的漏洞。


现在请记住我在回答之初提到的观点。如果在此答案中的任何时候您都认为“哦,是的,我没有考虑过”,那么我的观点就得到了证明。

您遇到了我所描述的Dave的错误格言:


如果我添加更多加密货币,它将更加安全。


这是开发人员的共同特征,我曾经也相信。它与否定其他原则(例如Kerckhoff原则)并驾齐驱。最终,您必须意识到并接受晦涩难懂不是安全轨道。这是弱加密的拐杖。如果您的加密货币很强大,则不需要拐杖。

评论


两者之间的相互作用是不确定的,因为没有人研究过它。将两者结合使用可能会提供更高的安全性,但也可能导致这些哈希的内部之间发生异常交互。一个很好的例子是一个时间垫。当k真正是随机的并且对攻击者未知时,计算c = m ^ k可以为您提供完美的安全级别。因此,让我们做两次,以提高安全性!因此,我们最终得到c = m ^ k ^ k,得出m。哦,天哪。显然,哈希之间的相互作用更为复杂,但是原理仍然存在。

–多项式
13年4月1日在13:09

我的观点是,由于我们不知道可能存在哪些潜在问题,为什么不采用已知的安全路线,而只使用具有适当工作因素的scrypt?它几乎可以满足所有目的的安全。

–多项式
13年4月1日在13:10

@多项式+1好答案。但是,直到我读到您对一次性垫的评论时,我才对您的答案中的bcrypt / scrypt部分感到确信。可能考虑将评论添加到您的答案中。

–菲尔
2013年4月1日下午14:02

我仍然不明白为什么scrypt(bcrypt(x))可能会成为问题。如果两者奇怪地交互,仅使用bcrypt并不能使其更加安全-攻击者可以简单地将您的bcrypt()内容加密为scrypt()。另外,如果有人想出一种更聪明的方式来猜测一种哈希算法的原始明文,那么他们可能不会同时为另一种算法找到更快的方法。有人合理地认为ROT13是一个很好的哈希机制。如果我使用ROT13(bcrypt(x)),当人们“破解” ROT13时,我是否还会变得更好?

– root
13年4月2日在9:46

@Brilliand:几乎可以肯定,攻击者将至少在某种程度上找到加速这两种算法的方法-可能数量不同。如果事实证明攻击者发现一种算法的加速比为100:1,另一种算法的加速比为2:1,那么对于使用每种算法进行了一半轮次的系统而言,攻击者将获得大约4:1的加速比。没有对方。除非有人知道哪个系统攻击者将拥有“更好的运气”,否则对冲押注似乎几乎是不合理的。

–超级猫
14-10-19在22:39

#2 楼

加密基元可以安全地堆叠,并且只有当您足够了解基元以了解其弱点以及这些弱点如何相互作用时,才能提高安全性。如果您不了解它们,或者不了解详细信息,那么,这就是获取Dave协议的方式。是安全的。这就是为什么它需要被发布和审阅的原因,如果未经审阅,您将无法知道它是否像scrypt一样强大,或者是否更接近CRC32。

所以,不是专家-您的东西很可能比您使用过的最弱的原语弱(请参阅Dave的协议),而您却一无所知。或至少在破解之前您不会知道–确定您的密码在Pastebin上并不是确定该方案有缺陷的理想方法。可以从深度防御的角度提供帮助,但是底层系统必须是安全的。
scryptbcryptPBDKF2之间-几乎每个平台都将至少支持其中之一。这些都是众所周知的,并且经过了良好的测试-它们提供不同级别的保护,但它们仍然比md5sha1的奇怪堆叠安全得多。

评论


我认为md5和sha1的堆栈是一个不好的例子,我永远不会使用它,而只是为了说明。我对bcrypt-scrypt堆栈特别感兴趣。我还是不明白怎么可能使哈希变弱?就像我说的那样,无论如何,如果黑客想要的话,这是一个可以采取的步骤,因此,即使它确实削弱了哈希,那么即使我不为他们做这也是一个巨大的问题!

–乔治·鲍威尔(George Powell)
2013年4月1日上午10:37

@GeorgePowell:黑客不仅对恢复原始的纯文本密码感兴趣。他可能还对发现碰撞感兴趣。通过将这些函数链接在一起,可能会增加冲突量。

–基督徒
2013年12月20日19:44

您能否解释一下,如果黑客可以访问数据库,为什么他们试图查找冲突?同样,哈希函数产生的冲突次数肯定是其质量的函数吗?如果对哈希进行哈希处理会导致更多冲突,那么我建议哈希函数一开始就很差。

–怪物
2015年11月24日10:00

#3 楼

对于将scrypt和bcrypt结合使用的特定问题,请记住,这些功能的成本是可配置的,并且您希望尽可能提高该成本,同时又要使其可以承受特定用途。例如,如果您可以将bcrypt最多使用X次迭代(超过此数量,对于服务器和平均每秒用户连接数而言,这太昂贵了),或者使用scrypt最多进行Y次迭代,则您不能使用scrypt(bcrypt)对于bcrypt使用X次迭代,然后对scrypt使用Y次迭代:这将超出您的CPU预算。一个人。您不能仅仅通过将它们串在一起来“兼顾两全”。实际上,您可以期望的最好成绩是两者之间的平均水平。而且这是以更复杂的代码为代价的,这在谈论安全性(或就此而言,可维护性)时固有地不好。

评论


大多数算法可能会随着时间变得更快,尽管不一定相等。假设方法X有1%的机会被加速100倍,并且有10%的机会被加速两倍。对于方法Y同样如此。除非我遗漏了某些东西,否则我认为以半强度运行这两种算法将意味着只有在两种构成算法都可行的情况下,复合材料才可能实现大幅提速。

–超级猫
2014年11月11日下午0:22

是的,另一个问题是规模经济。此处提及:security.stackexchange.com/questions/33531/…

–起搏器
16-09-10的2:47

#4 楼

除了亚当的答案外,我还要提及的是,每当您使用加密技术时,都应该有充分而不可避免的理由。在上面的示例中,这是不存在的。

md5(md5(salt) + bcrypt(password))
scrypt(bcrypt(password + salt))


bcryptscrypt算法已经足够强大,并且被认为牢不可破。您想解决什么问题?而且,您为什么认为结合他们的结果(尤其是与md5结合)可以解决问题?在最佳情况下,您可能仅将破解密码的难度降低为最弱哈希的难度,而实际上并未提高安全性。而且最糟糕的情况还无法确定。

它手动实现了一个重复的哈希方案,但是没有足够的回合才能真正对攻击者施加重要的工作因素。 >您在没有真正解决需要解决的问题的情况下抛弃了加密技术
,大大增加了在实现中引入缺陷的可能性
,您可能已将安全性降低到了最弱的散列算法中,并且
您已经介绍了一个未知的最坏情况,其中以前不存在


评论


问题的末尾提到了“我要解决的问题”或这样做的好处。而且我仍然不明白像sha1(md5(bcrypt()))这样的哈希堆栈可能比bcrypt更弱!请解释一下,如果将md5放在bcrypt之上使它变得更弱,那么为什么黑客在获得bcryt密码后才不自己做呢?

–乔治·鲍威尔(George Powell)
2013年4月1日上午10:57

@GeorgePowell您的sha1(md5(bcrypt()))方案没有任何意义。 bcrypt不能提供什么呢?如果要在bcrypt中寻求更高的安全性,为什么不增加工作系数或切换到scrypt?滥用其他散列图元,尤其是像MD5这样主要破坏的散列图元,以获得不确定的微不足道的好处(这实际上可能是不利的),这并不明智,只会给您带来更多的复杂性。

–多项式
13年4月1日在11:06

安全问题并不是真正的加密问题。您必须编写代码行才能产生此实现,并且编写的每一行都会带来潜在的漏洞。从安全的角度来看,即使是某些微妙的事情,例如在某些计算机上处​​理Unicode的方式,也可能是灾难性的。保持简单,使实施过程清洁无用,您将更加安全。

–多项式
13年4月1日在12:11

@GeorgePowell它没有帮助他们。想象一下,存在一个散列函数,其输出空间为一个单字节。如果我们在任何时候都使用密码来计算摘要(即使后来将密码传递给bcrypt之类的东西),那么对攻击者来说,暴力破解密码显然是微不足道的。但是这个弱哈希存在的事实不允许攻击者对我们使用它,因为我们没有使用它。

–斯蒂芬·托瑟(Stephen Touset)
2013年4月1日15:28



@GeorgePowell此外,您要解决的“问题”实际上并不存在。这纯粹是虚构的。如果它的存在,专业密码学家会争先恐后拼了命的放了一个永久的解决方案。您明显的信念是:1)存在实际问题,2)没有公开的解决方案,并且3)“解决方案”微不足道,同时还暗含着专业密码学家愚蠢和/或懒惰的断言。否则他们会想出解决办法的,对吗?

–斯蒂芬·托瑟(Stephen Touset)
2013年4月1日15:34



#5 楼

如果将不安全的操作应用于安全算法,则可以肯定会破坏哈希函数。您的新功能甚至可能比最薄弱的链接差很多。

为什么攻击者不使用此功能破坏安全功能?这对他们没有帮助。例如,如果我使用零加密覆盖了使用bcrypt安全存储的密码的前440位,那么我可以通过蛮力轻易找到匹配的密码,但是该密码仅适用于我自己的糟糕算法。一个理智的实现可能会拒绝它。

将大块哈希值零化显然是不好的,但是即使安全的操作也可以组合成危险的东西。将两个数字相加(模n以确保长度恒定)是“安全的”。通常,没有熵损失。但是,h(x)+ h(x)mod n会将哈希h(x)的质量降低一位,因为结果始终是偶数。同样安全的运算符XOR甚至更糟,因为h(x)XOR h(x)始终返回零。请记住,一如既往,发明一种足够好的方案以至于您自己不会发现任何弱点是微不足道的,但是要想发明一个无人能及的方案是非常困难的。

评论


好的答案,我想我明白要点:古怪的哈希值可以使通过暴力破解找到匹配项更加容易,但不能更容易地找到使用的原始密码。这就是为什么黑客没有必要自己应用较弱的哈希值。破解堆叠的哈希并不意味着破解内部哈希。

–乔治·鲍威尔(George Powell)
13年4月1日在11:20

#6 楼

哈希函数由密码学家构建,并由密码学家破坏。今天,仍然有许多强哈希函数和弱哈希函数在使用。程序员应该信任密码学家和哈希函数。如果哈希函数中曾经存在漏洞,那么您一定会在Internet上或通过同事听到有关此漏洞的信息,然后密码学家一定会对其进行深入调查。使用任何安全的哈希算法,唯一已知的弱点可能是蛮力攻击。

组合哈希函数几乎不会增加额外的安全性,并且您可能要添加的任何内容可能已经在该函数中实现了。 br />
对密码设置密码非常适合降低彩虹表的有效性,这样就不能仅仅“查找”密码。无论您是对函数进行两次哈希还是更改哈希函数,本质上都是在给密码加盐。而且大多数功能都包含一种简单的加盐方法,因此实际上无需实现此功能。

让我说我想创建自己的安全哈希,因为每个人都这样做。而且由于我不是密码学家,所以我将需要它“真正地”安全,因为当然,每个程序员都知道如何制作安全的哈希而不是使用已经创建的安全哈希。所以我创建了我的曲折哈希函数mod10(md5(sha5(sha1(bcrypt(password + salt))))))。不同的东西。当然,在这个愚蠢的示例中,很容易看到只有10种不同的可能输出。但是只需使用一个安全的哈希函数,就可以完全避免这种情况。您的攻击者将无法访问您的源代码,并且可能无法猜测您古怪的哈希,从而无法进行暴力破解


因此,我们假设攻击者掌握了包含哈希的数据库表。我认为攻击者很有可能也可以获取该网页文件。您运行这些服务的系统可能利用相同的漏洞利用程序,导致您无法使用数据库。设置了数据库服务器,以便公众无法直接访问它。另一方面,包含代码的Web服务器位于最前面。

#7 楼

每当您增加算法的复杂性,甚至增加更多代码行时,都会增加应用程序中的失败点。组合算法可能会产生意想不到的后果。这可能会导致某些提示或其他迹象,实际上会削弱系统的加密强度。

您在应用程序中使用的库越多,通常对应用程序的风险就越大。如果在一个实现中发现允许漏洞,代码执行等缺陷,则您的应用程序很容易受到攻击。如果您碰巧碰巧选择了另一种未被攻击的算法,那么暂时就可以放心使用(当然,您也可能倒霉)。

记住KISS:保持简单,愚蠢,否则您可能会迷失在复杂性中。

#8 楼

我将不同意一大堆比我聪明,在安全方面比我更有经验的人。所以我可能是错的。

改进自己的哈希函数是一个好主意-如果操作正确。请执行以下3个简单步骤。


找出现有哈希函数的弱点或缺陷。
改进您自己的没有此缺陷的哈希函数。
验证即兴哈希函数具有现有哈希函数的所有优势。

完成第3步后,不使用即兴哈希函数将是一个傻瓜。

评论


问题是您无法完成步骤3。世界上没有人能够单方面确定一种新的哈希算法很强大。这就是为什么为了获得认可,新的候选算法会经过大量多年的经同行评审的比赛,并且要经过大量的审查。您根本不知道某个算法在真空中是否安全。

– Xander
13年4月2日,0:54

@Xander,我无法完成任何一个步骤。所以对我来说,我不是即兴创作。虽然步骤3可能是最重要的,但步骤1是最基本的。如果您至少不能确定现有的安全哈希函数存在问题,那么为什么要浪费时间即兴使用新的哈希函数。

–emory
13年4月3日在1:04

#9 楼

当连接不同的散列函数时,因为担心一个散列函数,在应用下一个散列算法之前先应用salt至关重要,那么其中一个算法中的任何冲突弱点都不会污染正在使用的第二个散列函数:

scrypt(bcrypt(密码+盐)+盐)

但是我认为scrypt是一项既定技术,Argon 2i赢得了密码哈希竞赛,并且据信会更多安全和bcrypt已经存在了很长的时间,并且已经证明可以防止琐碎的绕行。如果未来的攻击者展示了如何简单地破坏氩2i(目前认为很难):

bcrypt(Argon2i(密码+盐)+盐)只需执行以下操作就不太可能出错:

scrypt(密码+盐)

bcrypt(密码+盐)

R记住,大多数违规是由于代码中的人为错误造成的,更好地简化代码并通过动态,静态分析和人工代码审阅者彻底检查代码,以确保没有sql注入攻击通过(记住始终对数据库查询进行参数设置!)

#10 楼

我已经从该线程中学到了很多东西,所以我想以一种易于理解的方式来组合不同的方法时可能产生的结果(当然,它并不适合所有情况): ,S = strong]:

Formula        | Example
---------------|-----------------
W(W) = W       | md5(sha1(pwd))
W(S) = W       | md5(bcrypt(pwd))
S(W) = W       | bcrypt(md5(pwd)) 
S(S) = S-      | bcrypt(scrypt(pwd)) //their interaction is unknown
W+S = W        | md5(pwd)+brcypt(pwd) 
S+S = W        | bcrypt(pwd)+scrypt(pwd)
W'+S" = S      | md5(pwd1)+brcypt(pwd2) //pwd1 != pwd2
S'+S" = 2S     | bcrypt(pwd1)+scrypt(pwd2) //pwd1 != pwd2
SUBSTR(W) = W  | substr(md5(pwd),n); //Shorter the string, the weaker
SUBSTR(S) = S- | substr(bcrypt(pwd),n); //Shorter the string, the weaker
S+x = S+       | bcrypt(pwd)+x   //x=Variable str. unrelated to pwd
S(S+x) = S-    | bcrypt(scrypt(pwd)+x) //x=Variable str. unrelated to pwd
ROT13(S) = S   | ROT13(bcrypt(pwd))  


我想在这里实现的目标是,以简单的方式表明这些组合在大多数情况下不会增加额外的安全性(因此增加的复杂性不值得)。

评论


S(S)= S-这样的笼统的说法是不可能的。正如上面的评论中的多项式所解释的,重复强大的哈希函数原则上可以导致完全无用的哈希。这些“公式”基于什么?

–乔治·鲍威尔(George Powell)
16年4月14日在17:54

@GeorgePowell:是的,S(S)可能会导致意外行为,从而可能导致无用的哈希。这就是为什么要标记为:S-,这意味着它的强度不如单独的S,因此不建议使用。由于我们没有指定实际的算法,因此我们不能100%确定它会产生无用的哈希,但是由于这种风险,应避免使用。这些“公式”没有任何科学依据,只是我尝试以一种简单的方式来表示这种交互作用,因此任何尝试“自己运行”的人都可以对期望的结果有所了解,并避免使用它们。

–lepe
16 Apr 15'0:57

@ lepe,W(S)= W?你确定吗?请参阅security.stackexchange.com/questions/33531/…

–起搏器
16-09-10的2:49

@Pacerier:要分析的一点是“碰撞概率”。如果使用MD5哈希bcrypt哈希,则会增加冲突的机会,从而降低其强度。同样,如果MD5哈希值遭到破坏,则直接强行执行MD5哈希值可能会更快,从而从公式中删除“ S”(取决于实现可能是一个大问题)。还有一点是,如果W算法存在安全缺陷,它也会使W(S)也存在缺陷。由于这些原因,不应将W(S)视为S或S +。最好单独使用S,以防止增加复杂性和不必要的风险。

–lepe
2016年9月12日,1:13

@ lepe,1)确保可以暴力破解W,但是暴力破解W可以提供S(password),而不是密码本身。换句话说,在强行使用W后,您又回到了平方1。请参阅上面指向Root评论的链接。 2)接下来,如果W算法存在安全漏洞,则无法使W(S)出现漏洞。 [续]

–起搏器
16-09-18在19:05