BCrypt是在C#中使用的好哈希算法吗?我在哪里可以找到它?

139

我了解到,在对密码进行哈希时,许多程序员建议使用BCrypt算法。

我在使用C#编程,想知道是否有一个好的BCrypt实现?我找到了这个页面,但我不确定它是否可信。

在选择密码哈希方案时需要注意什么?BCrypt是一个“好”的实现吗?

2个回答

163

首先是一些重要的术语:

哈希 - 将字符串转换为一系列字符的行为,这些字符无法还原为原始字符串。

对称加密 -(通常只称为“加密”)- 将字符串转换为一系列字符的行为,可以通过使用相同的加密密钥进行解密以恢复原始字符串。

彩虹表 - 包含特定哈希算法中散列的所有字符变体的查找表。

- 附加到原始字符串之前的已知随机字符串,然后对其进行哈希。

对于.NET Framework,Bcrypt尚未具有验证的参考实现。这很重要,因为无法知道现有实现中是否存在严重缺陷。您可以在此处获得.NET的BCrypt实现。我不了解足够的密码学知识来判断它是好还是坏的实现。密码学是一个非常深入的领域。不要尝试构建自己的加密算法。认真点。

如果您打算实现自己的密码安全措施(叹气),则需要执行以下几个操作:

  1. 使用一个相对安全的哈希算法
  2. 在哈希之前对每个密码进行加盐处理。
  3. 为每个密码使用唯一且较长的盐, 并将盐与密码一起存储。
  4. 要求使用强密码

不幸的是,即使你做到了这些,一个决心坚定的黑客仍然有可能破解密码,只不过需要更长的时间。这就是你的主要敌人:时间

bcrypt算法之所以有效,是因为它需要比MD5慢五个数量级的时间来哈希密码;(并且仍然比AES或SHA-512慢得多)。它迫使黑客花费更多的时间创建彩虹表来查找你的密码,从而大大降低了密码被破解的风险。

如果您对密码进行盐值哈希,并且每个盐值都不同,那么潜在的黑客需要为每个盐值变化创建一个彩虹表,仅仅为了得到一个经过盐值和哈希处理的密码的彩虹表。这意味着如果您有100万个用户,则黑客必须生成100万个彩虹表。如果您为每个用户使用相同的盐值,则黑客只需生成1个彩虹表即可成功破解您的系统。
如果您没有对密码进行盐值处理,则攻击者只需查找现有的Rainbow表(AES、SHA-512、MD5),并查看是否有匹配的哈希值。这个已经完成了,攻击者无需自己计算这些Rainbow表
即使如此,你必须使用良好的安全实践。如果攻击者可以成功地使用另一种攻击向量(XSS、SQL注入、CSRF、等等)进入您的站点,良好的密码安全性就没有意义了。这听起来像是一个有争议的声明,但请思考一下:如果我可以通过SQL注入攻击获取您所有的用户信息,或者我可以通过XSS获取您的用户给我他们的cookie,那么您的密码安全性多好都没有用处

其他资源:

  1. Jeff Atwood: .NET加密简化(对哈希进行概述非常好)
  2. Jeff Atwood: 我刚刚登录了你的账户
  3. Jeff Atwood: 你可能没有正确地存储密码
  4. Jeff Atwood: 速度哈希

注意:请推荐其他好的资源。我已经读了数十篇不同作者的文章,但很少有人像Jeff那样简明地写作。请在找到文章时编辑添加。


2
@Jacco 好主意,已添加。虽然这并不是很重要。您可以简单地使用登录时间戳作为盐。它的区别在于攻击者需要为每个盐重新计算彩虹表。这就是使它变得困难的原因,而不是它是随机选择的。使其随机会增加另一层混淆,但一旦攻击者能够看到您的数据库(这是导致我们所有痛苦的问题),这就毫无用处了。 - George Stocker
4
不一定,盐值不需要保密,只需要对于每个实例来说是独一无二的。由于全球唯一是不可能的,所以随机是次佳选择。此外,时间戳不是一个好的盐值,因为它的熵值不够高。 - Jacco
10
我对你的说法“如果他们能够成功使用XSS或SQL注入,好的密码安全就不重要了”持有异议。相反,如果他们能够成功地进行XSS或SQL注入攻击你的网站,那么好的密码安全性就更加重要了。关键在于“深度防御”——你应该在应用程序的每一层尽可能地加强安全性。 - jammycakes
3
当然可以。我的意思被忽略了:你不能只是说,“嘿,我们对密码进行哈希和加盐,‘没问题’!” - George Stocker
1
关于BCrypt需要强调的一点是,它不仅慢,而且可以配置成指数级慢。它的设计目的是为了跟上摩尔定律的发展。SHA/AES实际上是被设计成快速的同时保持安全性,因为明文被认为具有高熵值。BCrypt的优势在于密码哈希,因为它可以使用算法复杂度作为低输入熵的替代品。 - KeithS
显示剩余2条评论

80
不应该在.NET中使用BCrypt。您必须使用内置的.NET框架实现的PBKDF2。它是.NET中唯一可自由使用的、经过密码验证的NIST推荐算法
StackId先前使用了BCrypt,并出于这个原因转向PBKDF2:

对于那些好奇的人,我们正在使用PBKDF2对密码进行哈希处理。相关代码在此处(http://code.google.com/p/stackid/source/browse/OpenIdProvider/Current.cs#1135),通过几层间接调用。在早期版本中,我们使用了BCrypt;但是转向PBKDF2是因为它已经内置在.NET框架中,而BCrypt需要我们验证其实现(这不是一个小任务)。

Kevin Montrose, May 27 2011 (在GitHub上更新链接)

编辑:在加密术语中,“已验证”(verified)的含义似乎不容易被理解,已验证的实现意味着它在密码学上已经被证明没有错误。这个成本很容易达到20000美元或更高。我记得当我在研究 OpenSSL 时读到他们声称他们还没有完成整个验证过程,但如果您需要完全验证,他们可以为您指明正确的路径并提及相关成本。某些政府要求包括强制使用已验证的加密算法。

.NET 中的 bcrypt 实现尚未经过验证。使用未经验证的加密实现,您无法绝对确定其中没有故意的恶意错误,例如允许后门进入加密内容,或者由于意外的实现错误而导致密码学不安全的数据。

2014 年更新: 对于那些质疑使用已验证的加密算法的紧迫性的人,请看看 heartbleed hack 在 OpenSSL 中所造成的灾难。这就是使用未经验证的实现的代价。它很安全......直到你发现任何人都可以读取你的服务器的整个内存内容。

引入 Heartbleed 的更改的作者 Robin Seggelmann 表示,他“错过了验证包含长度的变量”,并否认提交有缺陷的实现的任何意图。在 Heartbleed 被披露后,Seggelmann 建议关注第二个方面,称 OpenSSL 没有被足够多的人审查。

这就是未经验证的实现的定义。即使是最小的缺陷也可能导致整个安全系统崩溃。

2015年编辑:移除了基于建议的语言,并用绝对语言进行替换。为了纪念,嵌入了原始的Kevin Montrose评论。


27
引用链接评论中的话:“[我们] 转向 PBKDF2,因为它已经内置在 .NET Framework 中,而 BCrypt 需要我们验证一个实现”。请注意,该评论并没有说算法更好,只是 SE Dev 团队认为内置的 PBKDF2 实现比外部库更值得信赖(这最终是一个判断)。 - Piskvor left the building
4
@Piskvor 我更新了我的回答。这不是关于SO团队认为安全的内容,而是在本质上被证明是安全的或者有希望是安全的之间做出的判断。当涉及到密码学时,后者是不可接受的。 - Chris Marisic
8
我想知道SO是如何将所有bcrypt哈希密码迁移到新的哈希算法中的?他们不需要使用新算法对原始密码进行哈希处理吗? - Dharmendar Kumar 'DK'
9
我认为你甚至不需要要求他们重置密码。在下次登录时(他们提供明文密码的情况下),我相信你可以这样做。 - Matt Kocaj
13
这是糟糕的建议,我很惊讶它有这么多赞。在托管语言中验证BCrypt实现比验证C中的完整SSL实现要简单得多得多。Heartbleed完全不相关;您最好提到PHP类型强制问题与哈希相等性检查。虽然在实践中大部分情况下适用,但PBKDF2是一种KDF,而不是密码哈希算法,而BCrypt更加适合。无论如何,使用Argon2会更加合理,这是目前有一个经过充分测试的C#库。 - Polynomial
显示剩余17条评论

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