如果我在将密码存储在数据库中之前对密码进行哈希处理,是否足以防止任何人对其进行恢复?

我应该指出,这仅与直接从数据库中获取有关,而与其他任何类型都没有关系攻击,例如强行执行应用程序的登录页面,客户端上的按键记录程序,当然还有橡胶软管密码分析(或现在称为“密码密码分析”)。

不会阻止这些攻击。

评论

还有这个Stackoverflow线程

有趣的是(如果我没看错的话)在提供巧克力/猜测之后,几乎相同数量的人透露了他们的密码。这是否意味着我们的IT专业人员更容易受到巧克力的影响? ;)

这个问题出现在博客上:security.blogoverflow.com/2013/09/about-secure-password-hashing

理想情况下,所有这些都应该是毫无意义的,因为没有人应该重用密码,然后密码本身就毫无价值。如果有人重复使用密码,他们只是在寻求惩罚。如果攻击者拥有数据库,那么他们已经可以抢走所有数据,而不仅仅是口令,因此,如果口令是唯一的,则对其进行散列无关紧要,因为它没有价值...

@SargeBorsch什么?很抱歉,但我无法以类似明智的方式理解您的评论,但是无论如何,它可能更多地属于信息安全聊天室?

#1 楼


注意:该答案写于2013年。在接下来的几年中,许多事情发生了变化,这意味着该答案应主要被视为2013年的最佳实践。



理论

我们需要对密码进行哈希处理,以此作为第二道防线。可以验证用户身份的服务器必定在其入口中的某些位置包含一些可用于验证密码的数据。一个非常简单的系统将只存储密码本身,而验证将是一个简单的比较。但是,如果一个敌对的局外人要一眼就能看出包含密码的文件或数据库表的内容,那么该攻击者将学到很多东西。不幸的是,在实践中确实会发生这种局部的只读破坏(备份磁带放置不当,已停用但尚未清除的硬盘,SQL注入攻击的后果-可能性很多)。请参阅此博客文章以进行详细讨论。

由于可以验证密码的服务器的整体内容足以确实验证密码,因此,获得了服务器只读快照的攻击者就在其中。进行离线字典攻击的位置:他尝试使用可能的密码,直到找到匹配的内容。这是不可避免的。因此,我们想使这种攻击尽可能地困难。我们的工具如下:


密码哈希函数:这些是令人着迷的数学对象,每个人都可以有效地计算它们,但没人知道如何对其进行求逆。对于我们的问题,这看起来不错-服务器可以存储密码的哈希值;当提供一个假定的密码时,服务器只需要对其进行哈希处理以查看它是否获得相同的值;但是,了解哈希并不会显示密码本身。

盐:攻击者相对于防御者的优势是并行性。攻击者通常会获取哈希密码的完整列表,并且有兴趣破坏尽可能多的密码。他可能会尝试并行攻击几个。例如,攻击者可能会考虑一个潜在的密码,对其进行哈希处理,然后将该值与100个哈希密码进行比较;这意味着攻击者分担了多个受攻击密码的哈希运算费用。预先计算的表(包括Rainbow表)也有类似的优化。

使用并行性的所有攻击的共同特征是,它们可以处理使用完全相同的哈希函数处理的多个密码。盐化不是使用一个哈希函数,而是使用许多不同的哈希函数。理想情况下,密码哈希的每个实例都应使用自己的哈希函数。盐是在众多哈希函数家族中选择特定哈希函数的一种方法。正确应用盐将完全阻止并行攻击(包括彩虹表)。

速度慢:计算机随着时间的推移而变得越来越快(英特尔联合创始人戈登·摩尔(Gordon Moore)根据其著名的法律将其理论化)。人的大脑没有。这意味着随着时间的流逝,攻击者可以“尝试”越来越多的潜在密码,而用户却无法记住越来越复杂的密码(或断然拒绝)。为了应对这种趋势,我们可以通过定义哈希函数以使用大量内部迭代(数千个,甚至数百万个)来使哈希处理固有地变慢。我们有一些标准的密码哈希函数;最著名的是MD5和SHA系列。从基本操作中构建安全的哈希函数远非易事。当密码学家想要这样做时,他们会努力思考,然后再努力,并组织一场比赛,各职能部门之间展开激烈的对抗。当数以百计的密码学家在某项功能上不休,scrap断不休,无所适从后,发现没有什么不好说的时候,他们开始承认也许可以将特定功能视为或多或少是安全的。这就是SHA-3竞赛中发生的事情。我们必须使用这种设计哈希函数的方式,因为我们没有更好的方法。从数学上讲,我们不知道安全哈希函数是否确实存在;我们只有“候选对象”(这是“无法破解”和“世界上没有人知道如何破解”之间的区别)。

基本哈希函数,即使作为哈希安全函数,不适用于密码哈希,因为:


它没有加盐,允许并行攻击(可以免费获得MD5或SHA-1的彩虹表,甚至需要自己重新计算);
方法太快了,随着技术的进步而变得越来越快。使用最新的GPU(即每个人都可以购买的现成的消费类产品),哈希率以每秒数十亿个密码计算。

所以我们需要更好的东西。碰巧将哈希函数和盐打散在一起并对其进行迭代比设计哈希函数要容易得多-至少,如果您希望结果是安全的。同样,您还必须依靠标准构造,这些构造在辩护密码学家不断遭受攻击后仍然可以幸免。

良好的密码散列函数PBKDF2来自PKCS#5。它通过迭代计数(整数,至少为1,没有上限),盐(任意字节序列,长度不受限制),所需的输出长度(PBKDF2可以生成可配置长度的输出)进行参数化,和“基础PRF”。实际上,PBKDF2始终与HMAC一起使用,而HMAC本身是基于基础哈希函数构建的构造。因此,当我们说“带有SHA-1的PBKDF2”时,实际上是指“带有带有SHA-1的HMAC的PBKDF2”。

已经在各种框架中实现(例如.NET附带)。
高度可配置(尽管某些实现不允许您选择哈希函数) ,例如,.NET中的一个仅用于SHA-1)。
收到的NIST祝福(对哈希与密钥派生之间的差异进行模运算;请参见下文)。 )。

PBKDF2的缺点:


仅CPU密集型,因此可以通过GPU进行高度优化(防御者是执行通用功能的基本服务器,例如一台PC,但是攻击者可以将预算花在更专业的硬件上,这将给他带来优势。
您仍然必须自己管理参数(盐生成和存储,迭代计数编码...)。 PBKDF2参数有一个标准的编码,但是它使用ASN.1,因此大多数人会尽量避免使用ASN.1(对于非专家来说,可能很难处理)。

bcrypt

bcrypt是通过重用和扩展称为Blowfish的分组密码元素来设计的。迭代计数为2的幂,比PBKDF2的可配置性差一点,但是足够了。这是OpenBSD操作系统中的核心密码哈希机制。

bcrypt的优点:


许多可用的各种语言实现(请参阅Wikipedia页面末尾的链接)。
对GPU更具弹性;这是由于其内部设计的细节。 bcrypt的作者如此自愿:他们重用了Blowfish,因为Blowfish是基于内部RAM表的,该RAM表在整个处理过程中不断被访问和修改。对于想使用GPU加速bcrypt的人来说,这会使生活变得更加艰辛(GPU并不擅长并行访问大量内存)。请参阅此处进行一些讨论。
标准输出编码包括盐,迭代计数和输出,是一种易于存储可打印字符的字符串。

bcrypt的缺点:


输出大小是固定的:192位。
虽然bcrypt擅长阻止GPU,但仍可以使用FPGA进行彻底优化:现代FPGA芯片具有许多小型嵌入式RAM块,在一个芯片中并行运行许多bcrypt实现非常方便。已完成。

输入密码的大小限制为51个字符。为了处理更长的密码,必须将bcrypt与哈希函数结合在一起(对哈希进行哈希处理,然后将哈希值用作bcrypt的“密码”)。已知将密码原语组合在一起是危险的(请参见上文),因此一般不建议使用此类游戏。

scrypt

scrypt是一种较新的结构(于2009年设计),它基于PBKDF2和称为Salsa20 / 8的流密码构建,但是这些只是围绕scrypt的核心优势(RAM)的工具。 scrypt被设计为固有地使用大量RAM(它会生成一些伪随机字节,然后以伪随机顺序重复读取它们)。 “很多RAM”是很难并行的。基本的PC擅长RAM访问,不会尝试同时读取数十个不相关的RAM字节。具有GPU或FPGA的攻击者会想要这样做,并且会发现困难。



一台PC,即确切地说是什么防御者在对密码进行哈希处理时将使用它,这是计算scrypt的最有效平台(或足够接近)。攻击者不再花钱在GPU或FPGA上就可以助一臂之力。
调节该功能的另一种方法:内存大小。



还是新事物(我的经验法则是至少要等待5年的一般曝光时间,因此在2014年之前不得进行scrypt的生产-但是,当然,最好让其他人在生产中尝试scrypt,因为这会带来更多的风险。)
没有那么多可用的,可用于各种语言的现成实现。
不清楚CPU / RAM的组合是否最佳。对于每个伪随机RAM访问,scrypt仍会计算哈希函数。高速缓存未命中大约需要200个时钟周期,一次SHA-256调用将接近1000个。这里可能还有改进的空间。
还需要配置另一个参数:内存大小。

OpenPGP迭代和盐腌S2K

我引用这一点是因为如果您使用GnuPG进行基于密码的文件加密,则将使用它。该工具遵循OpenPGP格式,该格式定义了自己的密码哈希函数,称为“简单S2K”,“盐腌S2K”和“迭代盐腌S2K”。在此答案的上下文中,只有第三个可以被视为“良好”。它被定义为一个很长的字符串(可配置,最大约65兆字节)的哈希,包括8字节盐和密码的重复。

就这些而言,OpenPGP的迭代和盐腌的S2K很不错;它可以被认为与PBKDF2类似,但可配置性较低。作为独立功能,您很少会在OpenPGP之外遇到它。密码,请使用基于良好哈希函数的crypt()函数的迭代和加盐变体,并进行数千次迭代。这是相当不错的。某些系统也可以使用bcrypt,这更好。

基于DES块密码的旧crypt()函数还不够好:


它在软件上较慢,但在硬件上较快,并且也可以在软件上变得较快,但只有在并行计算多个实例时才能使用(这种技术称为SWAR或“ bitslicing”)。因此,攻击者处于优势地位。
它仍然相当快,只有25次迭代。
它具有12位的salt,这意味着盐的重用会经常发生。
它会将密码截断为8个字符(忽略第8个字符),并且还会删除每个字符的高位(因此,您或多或少会陷入ASCII)。

错误的密码哈希函数

关于其他所有内容,尤其是人们不懈地发明的几乎所有自制方法。

由于某些原因,许多开发人员坚持自己设计功能,并且似乎假设“安全密码设计”的意思是“将可以想到的各种密码或非密码操作都汇集在一起​​”。请参阅此问题的示例。潜在的原理似乎是,完全混乱的指令混乱将使攻击者迷惑不解。但是实际上,开发人员本人会比攻击者更困惑于自己的创造。

复杂性很差。自制不好。新的不好。如果您还记得这一点,则可以避免99%的问题涉及密码散列,加密或什至一般的安全性。

Windows操作系统中的密码散列曾经令人生畏,现在只是糟糕(未加盐,未迭代的MD4)。

密钥派生

到目前为止,我们一直在考虑哈希密码的问题。一个紧密的问题是将密码转换为可用于加密的对称密钥。这就是所谓的密钥派生,这是当您“使用密码加密文件”时要做的第一件事。密码验证令牌,但是在生成对称密钥时很糟糕;反之亦然。但是这些例子是非常“人为的”。对于上述实用功能:


密码可能会被截断为所需大小,因此可以将密码哈希函数的输出作为对称密钥。
密钥派生只要“派生密钥”足够长,可以避免“通用原像”(攻击者很幸运,并且发现产生相同输出的密码),该函数就可以用作密码哈希函数。超过100位左右的输出就足够了。

确实,PBKDF2和scrypt是KDF,而不是密码哈希函数-并且NIST“批准”了PBKDF2作为KDF,而不是明确地作为密码散列者(但仅需很少的虚伪就可以阅读NIST的散文这样看来,似乎PBKDF2可以很好地散列密码。)相反,bcrypt实际上是一个分组密码(密码处理的大部分是“密钥调度”),这就是然后用于CTR模式以产生三个块(即192位)的伪随机输出,使其成为一种哈希函数。通过在CTR模式下将块密码用于更多块,可以将bcrypt变成KDF。但是,像往常一样,我们不推荐这种自制的转换。幸运的是,对于大多数用途而言,192位已经足够了(例如,使用GCM或EAX进行对称加密仅需要128位密钥)。

其他主题

有多少次迭代?

尽可能多!这种杂乱无章的哈希运算是攻击者和防御者之间的军备竞赛。您需要进行多次迭代,以使每个人都难以对密码进行哈希处理。为了提高安全性,鉴于服务器必须执行的其他任务,应将其设置为在服务器上可以承受的最大数量。越高越好。

冲突和MD5

MD5坏了:在计算上很容易找到很多成对的散列值相同的不同输入对。这些称为碰撞。

但是,冲突不是密码哈希的问题。密码哈希要求哈希函数能够抵抗原图像,而不是冲突。冲突是关于找到无限制地提供相同输出的消息对,而在密码哈希中,攻击者必须找到一条消息,该消息产生攻击者无法选择的给定输出。这是完全不同的。据我们所知,MD5在原像方面仍然(几乎)和以前一样强(存在理论上的攻击,在实践中仍然遥不可及)。

密码哈希中常用的MD5真正的问题是它非常快速且无盐。但是,与MD5一起使用的PBKDF2会很可靠。对于PBKDF2,您仍应使用SHA-1或SHA-256,但要使用公共关系。人们听到“ MD5”时会感到紧张。

盐的产生

盐的主要和唯一要点是尽可能独特。每当在任何地方重用salt值时,都有可能为攻击者提供帮助。

例如,如果将用户名用作salt,那么攻击者(或几个合谋的攻击者)可能会发现它值得建立彩虹表,当盐为“ admin”(或“ root”或“ joe”)时会攻击密码哈希功能,因为世界各地将有多个(可能很多)站点,这些站点的用户名为“ admin”。同样,当用户更改密码时,他通常会保留其姓名,从而导致盐的重复使用。旧密码是很有价值的目标,因为用户习惯在多个地方重复使用密码(众所周知,这是一个坏主意,并因此而做广告,但他们仍会这样做,因为这样做会使他们的生活更轻松),并且因为人们倾向于以“顺序”生成其密码:如果您知道鲍勃的旧密码是“ SuperSecretPassword37”,那么鲍勃的当前密码很可能是“ SuperSecretPassword38”或“ SuperSecretPassword39”。

获得唯一性的便宜方法是使用随机性。如果您从操作系统提供的加密安全PRNG(/dev/urandomCryptGenRandom() ...)以随机字节序列的形式生成盐(盐),则盐值将“具有足够高的概率唯一”。 16个字节就足够了,这样一来您就不会在生活中遇到盐冲突,这虽然过分但又足够简单。 UUID是生成“唯一”值的标准方法。注意,“版本4” UUID仅使用随机性(122个随机位),如上所述。许多编程框架提供了易于使用的函数,可以根据需要生成UUID,它们可以用作盐。

盐保密性

盐并不意味着是秘密的;否则我们称它们为钥匙。您不需要公开盐,但是如果您必须公开盐(例如,支持客户端哈希),则不必为此担心太多。盐是独一无二的。严格来说,salt只不过是在一大类函数中选择特定的哈希函数而已。

“ Pepper”

密码学家永远不能单单隐喻一个隐喻。他们必须通过进一步的类比和双关语来扩展它。 “胡椒粉”是关于使用秘密盐,即钥匙。如果您在密码哈希函数中使用“ pepper”,那么您将切换到另一种完全不同的密码算法;也就是说,您正在通过密码计算消息身份验证代码。 MAC密钥是您的“辣椒”。

如果您可以拥有一个攻击者将无法读取的秘密密钥,那么胡椒粉便有意义。请记住,我们使用密码哈希是因为我们认为攻击者可以获取服务器数据库的副本,或者可能是整个服务器磁盘的副本。典型的情况是一台服务器在RAID 1中有两个磁盘。一个磁盘发生故障(电子板炸毁-这种情况经常发生)。 sysadmin替换了磁盘,重建了镜像,没有数据由于RAID 1的魔力而丢失。由于旧磁盘功能异常,sysadmin不能轻易擦除其内容。他只是丢弃磁盘。攻击者搜索垃圾袋,检索磁盘,更换板,然后发现!他对整个服务器系统有完整的印象,包括数据库,配置文件,二进制文件,操作系统……英国人所说的全部财产。为了真正发挥作用,您需要进行特殊的设置,其中不仅仅包含带有磁盘的PC。您需要HSM。 HSM在硬件和操作过程上都非常昂贵。但是使用HSM,您可以只使用一个秘密的“ pepper”,并通过简单的HMAC(例如,使用SHA-1或SHA-256)处理密码。这将比bcrypt / PBKDF2 / scrypt及其繁琐的迭代效率更高。另外,在进行WebTrust审核时,使用HSM看起来非常专业。

客户端哈希

由于哈希的(故意)昂贵,所以这样做很有意义客户机-服务器情况,以利用连接的客户机的CPU。毕竟,当100个客户端连接到单个服务器时,这些客户端的总和比服务器强得多。

要执行客户端哈希,必须增强通信协议以支持发送salt回到客户。与简单的客户端发送密码到服务器协议相比,这意味着额外的往返。这可能不容易添加到您的特定案例中。

在Web上下文中,客户端哈希是困难的,因为客户端使用Javascript,而Javascript对于CPU密集型任务而言是相当贫乏的。

在SRP上下文中,密码哈希必须发生在客户端。 br />
结论

使用bcrypt。 PBKDF2也不错。如果您使用scrypt,则您将成为“稍早采用者”,并带有此表达式所隐含的风险;但这对科学进步是个好举动(“碰撞假人”是非常光荣的职业)。

评论


啊!没那么快。现在有一个定义新算法的公开竞赛;候选人提交的截止日期是3月31日。一些候选人的提交报告可能会详细解释为什么他们的候选人比scrypt更好。因此,从现在开始的两个月后,我们将有足够的信息来得出关于“ scrypt或not scrypt”的结论(例如,有人建议scrypt的“内存硬度”要比以前在多核服务器上设想的要贵) 。

–托马斯·波宁(Thomas Pornin)
14年2月12日,11:55

您使胡椒看起来只对HSM有用,而对HSM没有帮助。其目的是在不同的地方使用不同的盐,从而迫使攻击者破坏所有盐。通常,盐与用户名一起存储在db中,而Pepper存储在登录服务器中。从而造成一些泄漏,无法进行脱机猜测:数据库服务器损坏的RAID磁盘泄漏了,但是胡椒存储在Web服务器中;或者数据库是通过SQL注入获得的,但配置文件不是。

–Ángel
2014-09-13 22:34

对于所有工作因素,bcrypt不会再产生192位。当您的bcrypt库输出一个字符串时,该字符串将对192位和一些其他参数(盐和功因数)进行编码,并使用Base64衍生物获取可打印的字符,但是从密码上讲,仍然只有192位-这是可以用于密码验证,但不能用作KDF。这是通过修改算法来“修复”的,但是完全不建议这样做(如果您足够了解可以安全地进行此类修改,则不会提出该问题)。

–托马斯·波宁(Thomas Pornin)
15年3月10日在11:28

作为具有CS经验的人,作为开发人员,他拥有超过15年的专业经验,我想说的是,这是我一直以来最喜欢的SE答案。清晰,简洁,无偏见。感谢您的回答并提醒我为什么这些东西这么难。

–突破
16年4月5日在16:47

在这里获得Argon2更新会很棒。

–熊佳亚诺夫
17年2月8日在16:20

#2 楼

为了存储密码散列,您需要一种足够慢的算法,以免强行攻击不可行。给密码加盐将有助于抵御彩虹攻击,但不能抵御暴力攻击。为了存储密码哈希,您需要使用专门为此目的设计的算法。例如:


bcrypt

scrypt是新的但很有趣,因为它不仅使用可变的工作因数而且还使用难于记忆的功能。这会大大增加暴力攻击的成本,因为运行时间和内存需求都增加了。

评论


为什么您说盐无济于事?盐的密码学价值不是秘密的,而是附加的熵(通常密码很少)。

–AVID♦
2010-12-15 9:28

这并不是要阻止盐分,而是$ hash = MY_HASH($ salt。$ pass),其中MY_HASH是一种快速的哈希算法。我的编辑更清晰吗?

–奥兹古尔(Ozgur Ozcitak)
2010-12-15 10:19



@AviD,在盐问题上,有一些攻击案例基本上无济于事。如果您使用的是快速哈希算法(如ozgur所述),GPU破解将很快通过大量散列,而添加盐并不会真正减慢它的速度。关于此的一些有趣信息codahale.com/how-to-safely-store-a-password

–罗里·麦库恩(Rory McCune)
2010-12-15 10:37

另外,bcrypt已经将盐存储在哈希中,因此您不必担心。

–奥兹古尔(Ozgur Ozcitak)
2010-12-15 11:34

可能希望在慢散列函数h ^ k(x)系列的let k = 2 ^ stretch中包括let h(x)= hmac [sha-256,salt](x)。

– yfeldblum
2011年7月15日在4:34

#3 楼

可以通过对哈希的蛮力计算或通过使用Rainbow表(特定于所使用的算法)来恢复作为哈希值存储在数据库中的密码。

将彩虹表创建为字典文件或更常见的是给定字符集[az,AZ,0-9]的每个组合的一系列预先计算的值,这是常见的示例。

本质上,它们可以加快处理速度。通过允许在表中查找哈希值而不是要求攻击者为每个密码创建哈希来破解密码。可以在网上找到用于常见密码算法(例如NTLM,MD5等)的Rainbow表,这使得访问大量密码表非常简单。

有很多方法可以改进存储在数据库中的哈希值的安全性。

首先要使用每个用户的salt值,该值与哈希密码一起存储在数据库中。它不是要秘密的,而是用来减慢蛮力过程并使彩虹表不切实际使用的。

我看到的另一个附加组件是附加所谓的胡椒价值。这只是另一个随机字符串,但对所有用户而言都是相同的,并与应用程序代码一起存储,而不是存储在数据库中。这里的理论是,在某些情况下数据库可能会受到威胁,但应用程序代码不会受到威胁,在这种情况下可以提高安全性。但是,如果有多个应用程序使用相同的密码数据库,确实会带来问题。

帮助提高密码安全性的第三种方法是使用慢速密码功能,这不会这对单个用户产生了巨大影响,但将大大降低攻击者破解从数据库中检索到的密码的速度。有关此方法的更多信息,请点击此处

#4 楼

更新4:到2016年,自从2011年首次写这篇文章以来的5年中,硬件的改进和其他因素使比特币的哈希率提高了100,000多(!)。密码破解技术在软件结束。因此,用户应该在其密码的最小长度中添加更多的字符,并且需要增加迭代次数,而且我们所有人都确实需要准备转向使用更好的算法,例如Argon2。

更新3:在2015年的密码哈希竞赛中,获奖者Argon2。它被设计为“难以记忆”,以使破解者难以实现GPU实现;简单;高度可配置;如果经过时间的考验,这可能是向前迈出的重要一步,但是正如Thomas所指出的那样,是否存在比bcrypt和scrypt更为现代的密码哈希方法?闪亮的新算法,可能会给专业人士更多的时间来寻找弱点。

更新2:2013年,几位专家发起了密码哈希竞赛,该竞赛将带来改进和更有用的方法,并选择了获奖者到2015年。有关此需求的出色背景以及过渡期间的良好建议,请参阅Passwords ^ 12中的密码安全性:过去,现在,将来。请注意,越来越快的硬件的出现(如下所述)意味着需要诸如scrypt之类的内存密集型算法,而且bcrypt仍然像PBKDF2或crypt一样能够抵抗GPU攻击。 />这里的其他人指出,尽管MYSQL仍然没有弄清楚这一点,但仍需要通过盐类来防御暴力攻击。自从1978年Robert Morris和Ken Thompson发表关于Unix crypt的开创性论文以来,迭代的重要性就已经得到了关注。但是许多人(以及像Django一样的开发人员也是如此)显然仍然认为蛮力必须花费很长时间或非常昂贵,因此认为SHA-1的单个迭代对于密码哈希是可以的。 />不正确!摩尔定律和云计算已经赶上了我们。在现代台式机上破解长度为8((26 + 26 + 10)^ 8 = 62 ^ 8 = 218,340,105,584,896 = 218万亿个组合)的字母数字密码的SHA-1散列需要5天,如果租用则需要1小时一堆Amazon计算节点(实际生成彩虹表需要多长时间?-IT安全)

更新:比特币哈希功能

上最强大的有组织哈希功能地球(不包括可能的机密系统)是比特币采矿网络。 [截至2011年5月,它正在执行SHA-256散列,总速率超过11 Thash / s,即11 * 10 ^ 12 hash / s(到2016年为1700000 Thash / s-参见上面的更新4),而且最近该速率一直在迅速上升(图表)。矿工正在努力赚取估计的每周700,000美元的收益,按当前每比特币14美元的价格(图),每10分钟产生50个比特币的速度来开采。如今流行的硬件包括Radeon HD 5970 GPU,每个GPU总共具有3200个流处理器,并且可以执行约800 Mhash / s的速度。它的功耗也很节俭,约为2.3 Mhash / Joule。有关更多选择,请参见比特币采矿硬件比较。事实证明,亚马逊EC2上的GPU节点使用的是哈希效率较低的Nvidia Tesla GPU,并且它们的节点以当今的价格进行挖矿并没有成本效益。

这大约是世界前500名超级计算机的哈希能力之和的5.5 Thash / s估计容量的两倍,当然,这些超级计算机通常是为浮点性能而不是哈希而设计的。

当前的极端情况,如果此哈希功能被重定向到尝试破解密码,例如在比特币价格暴跌之后,使用非迭代的密码算法会令人担忧。使用全部94个打印字符的完全随机组合的8个字符的密码将在不到10分钟的时间内落下(94 ^ 8 /(11 * 10 ^ 12 * 60)= 9.2)。 10个字符的密码将少于57天(94 ^ 10 /(11 * 10 ^ 12 * 3600 * 24)= 56.7)。即使完全随机化,由10个字符组成的大写小写字母数字密码(26 + 26 + 10 = 62个可能的字符)也将花费不到一天的时间(62 ^ 10 /(11 * 10 ^ 12 * 3600 * 24)= 0.88)。

但是,如果程序员只是简单地使用例如如Thomas所建议的那样,如果迭代次数为2000,那么10个字符的良好密码将持续数年。尽管很容易破解8个字符的密码,但在13天内(2000 * 94 ^ 8/11 10 ^ 12/3600/24 = 12.8天)。

另请参阅:


暴力破解算法错误的问题与其他从影子文件中恢复密码的方法-IT安全性


如何在应用程序/服务器级别防止暴力破解


评论


具有真实数字的出色书写。我猜想加密货币哈希集合现在在5年后具有更大的功能。

–起搏器
16 Sep 10'2:17



#5 楼

密码必须始终是哈希值,但这并不意味着不可能存在暴力破解攻击。关于存储和管理用户密码,应采取其他措施。我强烈推荐Solar Designer撰写的有关以下主题的文章:http://php-security.org/2010/05/26/mops-submission-10-how-to-manage-a-php-applications-users-and- passwords / index.html。

评论


散列的好处仅限于直接数据库访问,对通过应用程序进行暴力破解没有任何影响。

–AVID♦
2010-11-14 13:42

#6 楼

密码在存储前应先加盐并拉伸。基本上,这涉及到在密码后面附加或添加一些文本,并对结果进行哈希处理多次。至于散列算法,目前建议使用MD5和SHA-1以外的任何格式-选择SHA 256或512(请参见http://www.schneier.com/blog/archives/2009/06/ever_better_cry.html)

评论


多次对密码进行哈希处理真的有很多价值,尤其是在使用快速算法时?

–乔什·安德森(Josh Anderson)
2012年3月15日在6:24

developers.stackexchange.com/questions/115406/…

–内夫·斯托克斯
2012年3月15日在9:45

这不是一个好建议-此答案建议使用快速哈希,这是一个非常糟糕的主意(如其他答案中所述)。

– D.W.
2014年10月31日17:49

#7 楼

一个好的密码散列算法必须包含一些盐和一些东西,以使密码的计算变得昂贵(通常是迭代计数)。

最佳,最常用的方法是PBKDF2。尽管并不完美,但它应该是每个人的基准:

http://en.wikipedia.org/wiki/PBKDF2

评论


它不是“最常见”或“最佳”。最常见的是crypt()系列哈希,甚至是无盐的变体。 KDF并非为此目的而设计,因此请谨慎使用。不知道什么是“最佳”(我猜这取决于您的目标),但是bcrypt和scrypt甚至sunmd5更具用途。

–eckes
2012年11月22日20:07

#8 楼

我赞同PBKDF2的建议。它并不是计算上最昂贵的,但是它在实现过程中确实有一个精确的参考标准,并且受到了人们的广泛接受。

不过,我真的建议您阅读Colin Percival关于scrypt的论文。他很好地描述了这里发生的问题。我猜想随着时间的推移scrypt会越来越好。

http://www.tarsnap.com/scrypt.html

拥有可实施的标准并非没有,方式-如果有内存,则论文中描述的算法与bcrypt和scrypt中的参考实现之间存在差异。

#9 楼



首先,您应该对它们加盐,这基本上意味着在密码后面附加或添加一些文本。

,那么您应该使用强大的算法(md5不会削减)

评论


+1与算法有关,但您能说出哪种算法好吗?

–AVID♦
2010年11月13日在16:29

SHA-1被认为是安全的-> en.wikipedia.org/wiki/SHA-1

–托比
2010-11-15 20:30

NIST目前正在逐步淘汰SHA-1,并且不赞成将其用于新工作。维基百科文章对此进行了解释,该文章依次指向:csrc.nist.gov/groups/ST/toolkit/documents/shs/…

– pboin
2010-11-17 15:59



@keisimone SHA-2直到SHA-3出现为止,但是您应该使用多轮哈希算法使暴力破解成为挑战。使用SHA-2或bcrypt / scrypt的PKDBF2是合适的。

–理查德·加兹登(Richard Gadsden)
2011年7月7日在13:41

@RichardGadsden评论的所有这些简短的建议都是可怕的。 SHA-2不适合用于密码的哈希算法,因为它速度很快。 PBKDF2(迭代哈希)在某种程度上有所改善,但可能不如bcrypt或scrypt那样好。重申一遍:简单地添加密码并在其上运行SHA-256远远不够。

–斯蒂芬·托瑟(Stephen Touset)
2012年11月11日下午2:19

#10 楼

有趣的是,尽管bcrypt和scrypt都是密码的良好解决方案,但对后者有所帮助,但scrypt似乎容易受到缓存定时攻击。如此处建议的那样:http://eprint.iacr.org/2013/525卡特纳(Catena)可以避免这种情况,并具有可证明的安全性和其他一些不错的功能。

评论


1)很久以来,众所周知,scrypt的直接实现可能容易受到定时攻击。 2)我还不相信catena的安全声明。我认为它容易受到t ^ 1.5复杂度的攻击,因此无法达到所要求的t ^ 2安全性。 3)我相信,比起在catena中使用可预测的内存访问,创建掩盖内存访问模式的scrypt(或类似构造)的实现是一条更有希望的途径。

– CodesInChaos
2013年9月6日上午10:50

我要等到密码哈希竞赛结束后,才选择在竞争中表现良好的方案。在此之前,最好使用bcrypt或scrypt。如果catena确实如其声称的那样好,那它将是一个强有力的竞争者。但不幸的是,我认为并非如此。

– CodesInChaos
2013年9月6日上午10:51

#11 楼

据说bcrypt在GPU上速度较慢,这使得暴力破解速度较慢。但是,随着计算机硬件的不断发展,我们不仅应该依靠在特定硬件上实现特定哈希算法的难度。

,您可以通过使用“某些哈希函数支持的“可变工作/成本因素”(有时也称为“回合”)。其中包括bcrypt和SHA-512。

Glibc的crypt()函数允许为某些哈希算法指定轮数。例如,SHA-512的成本因子100000使散列的生成(并因此强行执行)比bcrypt的成本因子08慢约4倍。这可以通过使用诸如hashcat之类的哈希解决程序来确认。一个工作因素,仍然使它们变得太昂贵,同时又不通过常规的用户身份验证使服务器的CPU过载。

长密码和随机密码的重要性仍然适用。

我刚刚写了一篇有关细节的博客文章。

#12 楼

tsk tsk,尝试通过慢速加密保护系统是一个愚蠢的事情。例如,让我们说相反的话,我们有一个哈希,我们想获取密码(如果有的话,还要加盐) )。

即使我们每秒要运行数十亿个哈希,我们也需要一种方法来匹配该值。例如,让我们说下一个值:
/>

SALT:IT_ISASALT它是哈希:7D371ADDB8862FD3B8320020B0C6B52BEE716A8204CA18B03C9A6B4686EEB610
-> SALT + VALUE。

一种实现它的方法是,加密一个值,然后尝试比较某些字典中是否存在该值的一部分。例如,我们测试了一个组合,发现:


aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434dHORSE(“ horse”是我们的字典中存在的单词)。


这是正确的值吗?我们不知道,但是可能如此,因此我们必须存储此组合,然后尝试其余的组合。这是一个缓慢的过程,需要大量内存。但是即使有可能,我们仍然可以发现很多虚假的价值。因此,我们可以将匹配从2 ^ 256个组合减少到2 ^ 100个或更多组合。为此,我们需要某种方法来找到正确的匹配项。如果SALT不平凡,那么此任务可能会花费大量时间和资源,并且成功的机会仍然很慢。

现在,我们可以生成一个新的哈希值(例如,我们创建了一个虚假帐户),因此我们知道了值和哈希值(但盐)。它大大简化了操作,因为找到匹配项等于找到以我们的值结尾的文本(例如:123456)。但是,如果盐不是以SALT + VALUE的形式生成,而是以SALT1 + VALUE + SALT2的形式生成,或者如果SALT + VALUE2(其中VALUE2是使用我们不知道的某种算法修改的值)怎么办。

现在,假设我们的哈希值生成如下:


hash256(SALT + hash256(SALT + VALUE))



如果SALT是秘密的,那么就没有自动的方法来匹配或找到原始值。
即使我们有一台计算机可以在一秒钟内生成所有可能的hash256(所谓的Quantum Computer),我们也需要一个找到哪个值正确与否的方法,这将需要大量资源。

因此,结论是:


与查找生成的哈希是否匹配的算法相比,hash毫无意义。您可以尝试生成100万,10亿或1万亿个哈希,并且不会改变主要问题,我们需要找到一种方法来确定(这十亿个哈希中的)一个是否正确。
它与熵无关。在这种情况下,与现实相比,熵只是一个数。



评论


那是错误的。您基本上是在通过模糊来暗示安全性,而且一次又一次地说过,如果它依赖于攻击者不知道该方案,那么该方案就无法保证其安全。

–MechMK1
19年7月20日在11:27

否。我的意思是,如果SALT安全并且存储的值不是基于字典的,那么这是安全的(因此,生成了哈希值的两倍)。使用bcript或某些慢速算法只是没有意义,而概率的数目也没有意义。我也明确指出:假设我们每秒可以产生10亿个哈希,那又如何呢?我们如何找到正确的哈希?这就是挑战。因此,散列的生成速度只是其中一部分。

–麦哲伦
19年7月20日在14:55

啊!嘘。但是我是对的(并且它显示了证据),显然,许多安全专家从未尝试过对其进行破解。最好的无知。

–麦哲伦
19年7月20日在15:15

同样,隐蔽性的安全性也起作用。如果该算法不是公开的,则不可能破坏安全性。散列的大小可以揭示算法的一部分,但仅此而已。

–麦哲伦
19年7月20日在15:19

拖钓的不错尝试。就像这样说:您通过模糊保护您的系统,我将通过设计来保护我的系统。

–MechMK1
19年7月21日在15:24

#13 楼

我在这里使用SHA1

def __encrypt(self, plaintext, salt=""):
    """returns the SHA1 hexdigest of a plaintext and salt"""
    phrase = hashlib.sha1()
    phrase.update("%s--%s" % (plaintext, salt))
    return phrase.hexdigest()
def set_password(self, new_password):
    """sets the user's crypted_password"""
    #from datetime import datetime, timedelta  
    import datetime
    if not self.salt:
        self.salt = self.__encrypt(str(datetime.datetime.now()))
    self.crypted_password = self.__encrypt(new_password, self.salt)
def check_password(self, plaintext):
    return self.__encrypt(plaintext, self.salt) == self.crypted_password


而不是像这样给密码加盐,我希望算法已更改,因此它不需要加盐并且仍然不会散列密码。相同的输入两次达到相同的值。

评论


这是一个问题还是一个答案?

–PaŭloEbermann
2011年8月19日在1:44

“这是关于一个问题还是一个答案的问题?”

–尼古拉斯·R。
2012年6月11日9:33

这是一个非常破损的实现,应突出显示它作为不实现密码哈希的示例。首先:SHA1不合适,因为它非常快。第二:盐必须是唯一的,并且不可猜测。虽然使用当前时间并不是很糟糕,但是根本不够好。

–斯蒂芬·托瑟(Stephen Touset)
2012年11月11日在2:24