【问题标题】:Passwords and different types of encryption密码和不同类型的加密
【发布时间】:2010-11-09 09:31:20
【问题描述】:

我知道,我知道,类似的问题已经被问过数百万次了,但由于大多数问题都有不同的味道,我有一个自己的问题。

目前我正在开发一个旨在在我的国家/地区推出的网站,因此需要对用户系统进行某种保护。

我最近读了很多关于密码加密、散列、加盐的文章。但在阅读了那么多文章之后,我感到困惑。

有人说普通的 SHA512 加密对于密码就足够了,其他人说无论你做什么都必须使用“盐”,然后有人说 你应该建造一台全新的机器用于密码加密,因为这样没人能得到它

现在我将hash_hmac(); 与 SHA512 一起使用,另外,密码获取随机 SHA1 盐,最后一部分定义为随机 md5();钥匙。对于我们大多数人来说,这听起来很安全,但是是吗?
我最近在 SO 上读到这里,bcrypt();(现在称为 crypt(); 和 Blowfish 散列)是最安全的方式。在阅读了关于 crypt(); 和相关内容的 PHP 手册后,我很困惑。

基本上,问题是,我的 hash_hmac(); 会打败 Blowfished crypt();,反之亦然吗?

另外,也许还有更安全的密码散列选项?

【问题讨论】:

  • 引用:没有万无一失的系统可以满足傻瓜的聪明才智!取消报价。放置一个成本和复杂性低于它应该保护的锁。
  • @Kangkan 同意,但傻瓜不会使用该网站,大多数用户不会玩帐户黑客攻击。我只是愿意创建一个不太复杂但安全的密码哈希,因此,就最佳选择征求“老手”的建议。
  • 看下一句。因此,如果您打算保护的数据的价值不是太高,那么您现在所做的任何事情都足以满足需求。您正在使用哈希和盐,可以很好地处理蛮力攻击。此外,您可以考虑在 HTTPS 通道上进行身份验证。这将减少中间人攻击的问题。
  • HTTPS 需要证书,不是吗? 从未关注过 HTTPS,如果我错了,请纠正我
  • 您可以对 HTTPS 证书进行自签名。现在用户会被警告它是由不受信任的一方签名的,但是如果你的用户很聪明并且你解释了这个消息,这不应该是一个问题。

标签: encryption hash passwords


【解决方案1】:

正确应用密码学的关键是足够精确地定义您所追求的属性。

通常,当有人想要散列密码时,它是在以下情况下:服务器正在验证用户;用户通过机密通道(HTTPS ...)显示他们的密码。因此,服务器必须存储用户密码,或者至少存储一些可用于验证密码的东西。我们不想“按原样”存储密码,因为获得对服务器数据库的读取访问权限的攻击者随后将获悉所有密码。这是我们的攻击模型

密码是适合普通用户大脑的东西,因此不能完全猜不透。少数用户会选择具有高熵的非常长的密码,但大多数用户会选择熵不高于 32 位的密码。这是一种说法,攻击者必须平均“尝试”不到 231(约 20 亿)个潜在密码,然后才能找到正确的密码。

无论服务器存储什么,验证密码就足够了;因此,我们的攻击者拥有尝试密码所需的所有数据,仅受他可以召集的计算能力的限制。这被称为离线字典攻击

必须假设我们的攻击者可以破解一个密码。在这一点上,我们可能希望有两个属性:

  1. 破解单个密码应该很困难(几天或几周,而不是几秒钟);
  2. 破解两个密码应该是破解一个密码的两倍

这两个属性需要不同的对策,可以结合使用。

1.慢散列

哈希函数很快。计算能力很便宜。作为一个数据点,使用 SHA-1 作为散列函数和 130 美元的 NVidia 显卡,我每秒可以散列 1.6 亿 个密码。 231 费用在大约 13 秒内支付。因此,SHA-1 对于安全性来说太快了。

另一方面,用户不会看到在 1µs 内进行身份验证和在 1ms 内进行身份验证之间有任何区别。所以这里的技巧是以一种使其变慢的方式扭曲散列函数。

例如,给定一个散列函数H,使用另一个散列函数H'定义为:

H'(x) = H(x || x || x || ... || x)

其中 '||' 表示串联。简单来说,重复输入足够多的时间,以便计算 H' 函数需要一些不可忽略的时间。所以你设定了一个时间目标,例如1ms,并调整达到该目标所需的重复次数。 10 毫秒意味着您的服务器将能够以仅 10% 的计算能力为代价每秒验证 10 个用户。请注意,我们讨论的是存储哈希密码的服务器以供其不可告人的用途,因此这里不存在互操作性问题:每个服务器都可以使用特定的重复计数,为其功能量身定制。

现在假设攻击者可以拥有你 100 倍的计算能力;例如攻击者是一个无聊的学生——许多安全系统的克星——并且可以在他的大学校园内使用数十台计算机。此外,攻击者可能会使用哈希函数 H 的更彻底优化的实现(您说的是 PHP,但攻击者可以进行汇编)。此外,攻击者耐心:用户不能等待超过几分之一秒,但一个足够无聊的学生可能会尝试几天。然而,尝试 20 亿个密码仍需要大约 3 天的计算时间。这最终并不安全,但比在一台廉价 PC 上运行 13 秒要好得多。

2。盐

salt 是您使用密码散列以防止共享的一段公共数据。

“共享”是指当攻击者可以对多个被攻​​击的密码重复使用他的哈希值时,就会发生这种情况。当攻击者有多个散列密码时会发生这种情况(他读取了散列密码的整个数据库):每当他散列 一个 潜在密码时,他可以对照 all 进行查找他试图攻击的散列密码。我们称之为并行字典攻击。共享的另一个实例是攻击者可以构建一个预先计算的哈希密码表,然后重复使用他的表(通过简单的查找)。传说中的 彩虹表 只是预计算表的一个特例(这只是时间-内存权衡,它允许使用比硬盘上的预计算表大得多的预计算表;但是构建该表仍然需要散列每个潜在的密码)。时空方面的并行攻击和预计算表是相同的攻击。

腌制胜过分享。 salt 是一个 public 数据元素,它改变了散列过程(可以说 salt 在一组不同的函数中选择散列函数)。盐的重点是每个密码都是唯一的。攻击者无法再共享破解工作,因为任何预先计算的表都必须使用特定的盐,并且对于使用不同盐散列的密码是无用的。

盐必须用于验证密码,因此服务器必须为每个散列密码存储用于散列该密码的盐值。在数据库中,这只是一个额外的列。或者您可以将盐和哈希密码连接在一个 blob 中;这只是数据编码的问题,由您决定。

假设 S 为盐(即一些字节),密码 p 的散列过程为:H'(S||p) em>(使用上一节中定义的 H' 函数)。就是这样!

盐的重点是尽可能地对每个散列密码唯一。实现此目的的一个简单方法是使用随机盐:每当创建或更改密码时,使用随机生成器获取 16 个随机字节。 16 字节应该足以使盐重用非常不可能。请注意,每个密码的salt应该是唯一的:使用用户名作为salt是不够的(一些不同的服务器实例可能有同名的用户——存在多少个“bob”那里?——还有,一些用户更改他们的密码,新密码不应该使用与以前密码相同的盐)。

3.哈希函数的选择

H' 散列函数建立在散列函数 H 之上。一些传统的实现使用加密算法扭曲成散列函数(例如 DES 用于 Unix 的 crypt())。这促进了“加密密码”表达的使用,尽管它不正确(密码没有加密,因为没有解密过程;正确的术语是“散列密码”)。然而,使用专为散列目的设计的真正散列函数似乎更安全。

最常用的哈希函数有:MD5、SHA-1、SHA-256、SHA-512(后两者统称为“SHA-2”)。在 MD5 和 SHA-1 中发现了一些弱点。这些弱点对一些的使用有严重的影响,但不是上面描述的(这些弱点是关于碰撞的,而我们在这里工作的是抗原像性)。不过,公关还是选择 SHA-256 或 SHA-512 更好:如果你使用 MD5 或 SHA-1,你可能需要为自己辩解。 SHA-256 和 SHA-512 的输出大小和性能不同(在某些系统上,SHA-256 比 SHA-512 快得多,而在其他系统上,SHA-512 比 SHA-256 快)。然而,性能在这里不是问题(不管散列函数的内在速度如何,我们通过输入重复使它慢得多),并且 SHA-256 输出的 256 位已经绰绰有余。为了节省存储成本,将散列函数输出截断到前 n 位,在密码学上是有效的,只要您保留至少 128 位 (n >= 128)。

4.结论

每当您创建或修改密码时,都会生成一个新的随机盐 S(16 个字节)。然后将密码 p 散列为 SHA-256(S||p||S||p||S||p||...||S||p) em>,其中 'S||p' 模式重复了足够多的时间,以至于散列过程需要 10 毫秒。存储 S 和哈希结果。要验证用户密码,请检索 S,重新计算哈希值,并将其与存储的值进行比较。

你会活得更久,更快乐。

【讨论】:

  • 这是一个非常棒的答案。比我自己的要好得多:) +1
  • +1 以获得全面的答案。还喜欢你包括通道的安全性(HTTPS)。如果钥匙可以在途中被发现,那么最高级别的安全系统将毫无价值。
【解决方案2】:

这个问题提出了多个问题,每个问题都需要单独解决。

首先,您应该设计自己的加密算法。某些东西是安全的,因为它不是主流的说法是完全无效的。您可能开发的任何算法都只会与您对密码学的理解一样强大。

一般的开发人员不掌握创建强大算法所需的数学概念,如果您的应用程序受到攻击,那么您完全未经测试的算法将成为攻击者和您的用户个人信息之间唯一的东西,并且有适当动机的攻击者可能会比您使用经过时间考验的算法更快地破解您的自定义加密。

使用盐是个好主意。由于哈希值是同时使用盐值和密码值生成的,因此对哈希数据的暴力攻击变得过于昂贵,因为攻击者使用的哈希密码字典不会考虑生成哈希值时使用的盐值。

我不是最有资格评论算法选择的人,所以我将把它留给其他人。

【讨论】:

  • 很好的答案,但我不愿意开发自己的算法,只想找出最好的。由于没有最好的这样的东西,我想根据高级程序员/密码学家/等的答案找出我对这个问题的解决方案。
【解决方案3】:

我不是 PHP 开发人员,但我有一些加密方面的经验。我的第一个建议是像 Crippledsmurf 建议的那样,绝对不要尝试“推出自己的”加密。它会写满灾难。

你说你目前正在使用hash_hmac()。如果您只是保护用户帐户和一些基本信息(姓名、地址、电子邮件等),而不是任何重要的东西,例如 SSN、信用卡,我认为您可以安全地坚持现有的信息。

通过加密,我们都希望使用最安全、最复杂的保险库来保护我们的资料,但问题是,为什么要有一扇巨大的安全门来保护没人真正想要的东西?您必须平衡您使用的加密类型和强度与您所保护的内容和被采取的风险。

目前,如果您正在加密您的信息,即使是在基本级别,您已经击败了 90% 的网站和应用程序 - 它们仍然以纯文本形式存储。您正在使用盐(好主意),并且使解密信息变得极其困难(md5 密钥很好)。

打个电话 - 这值得进一步保护吗?如果没有,请不要浪费时间继续前进。

【讨论】:

  • 嗯,有趣的是,从未真正考虑过诸如我要保护的数据之类的事情或类似的事情...看起来,是的,我当前的选择就足够了。谢谢你把事情弄清楚了。
猜你喜欢
  • 2017-07-06
  • 2018-11-28
  • 2012-10-03
  • 1970-01-01
  • 2015-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-22
相关资源
最近更新 更多