我们目前正在为我们拥有的网络应用程序存储纯文本密码。

我一直主张改用密码哈希,但另一位开发人员表示,这会不太安全——更多的密码可以匹配哈希,而字典/哈希攻击会更快。

这个论点有道理吗?

有帮助吗?

解决方案

绝对没有。但没关系。我之前也发过类似的回复:

不幸的是,人们,甚至程序员,都太情绪化了,不会轻易被争论所左右。一旦他对自己的职位投入了精力(如果你在这里发帖,他就是这样),你不可能仅用事实来说服他。你需要做的是转移举证责任。你需要让他出去寻找他希望能说服你的数据,并通过这样做了解真相。不幸的是,他享有现状的好处,所以你的路很艰难。

其他提示

维基百科

一些计算机系统存储了用户密码,可以将用户登录尝试(作为clearText)进行比较。如果攻击者可以访问此类内部密码存储,则所有密码,因此所有用户帐户都将受到损害。如果某些用户在不同系统上使用相同的帐户密码,则这些密码也将受到损害。

更安全的系统将每个密码存储在密码受保护的表单中,因此,对于获得内部访问系统的窥探者而言,对实际密码的访问仍然很难,而用户访问尝试的验证仍然是可能的。

一种通用的方法仅存储明文密码的“哈希”形式。当用户在此系统上键入密码时,密码处理软件通过加密哈希算法运行,如果从用户的条目中生成的哈希值与存储在密码数据库中的哈希相匹配,则允许用户访问用户。哈希值是通过将加密哈希函数应用于由提交密码组成的字符串以及通常称为盐的另一个值来创建的。盐阻止攻击者构建通用密码的哈希值列表。MD5和SHA1经常使用加密哈希功能。

您可以在该页面上阅读有关该主题的更多内容。在我看来,在我阅读和使用过的所有内容中,散列是一个更好的方案,除非您使用非常小的(< 256 位)算法。

绝对没有理由在网络应用程序上保留纯文本密码。使用带有盐值的标准散列算法(SHA-1,而不是 MD5!),因此彩虹攻击是不可能的。

我不明白你的其他开发人员如何看待“更多密码可以匹配哈希值”。

有人认为“哈希攻击会更快”,但前提是您在哈希密码时不加盐。通常,散列函数允许您提供盐,这使得使用已知的散列表浪费时间。

就我个人而言,我会说“不”。基于上述事实,以及如果您确实以某种方式获得明文暴露,那么加盐的哈希值对于试图进入的人来说没有什么价值。散列还提供了使所有密码“看起来”相同长度的好处。

即,如果对任何字符串进行哈希处理始终会生成 20 个字符的哈希值,那么如果您只查看哈希值,则无法判断原始密码是 8 个字符还是 16 个字符。

我在工作场所遇到了完全相同的问题。为了让他相信散列更安全,我所做的就是编写一个 SQL 注入,从我们网站的公共部分返回用户和密码列表。它立即升级为重大安全问题:)

为了防止字典/哈希攻击,请确保对每个用户唯一且静态的令牌进行哈希处理(用户名/加入日期/用户 GUID 效果很好)

如果您不对密码加盐,则怀疑您受到彩虹表攻击(具有给定哈希的有效输入的预编译字典)

如果您以明文形式存储密码,其他开发人员应该停止谈论安全性并开始阅读有关安全性的内容。

冲突是可能的,但对于密码应用程序来说通常不是一个大问题(它们主要是在使用哈希作为验证文件完整性的方式的领域中的问题)。

所以:对您的密码加盐(通过将盐添加到密码的右侧*)并使用良好的哈希算法,例如 SHA-1,最好是 SHA-256 或 SHA-512。

附:关于哈希的更多细节 这里.

*我有点不确定盐是否应该放在字符串的开头或结尾。问题是,如果发生冲突(两个输入具有相同的哈希值),将 Salt 添加到“错误”的一侧不会更改生成的哈希值。无论如何,Rainbow Tables 不会出现大问题,只会出现碰撞

有句老话说,程序员假装是密码学家:)

杰夫·阿特伍德 (Jeff Atwood) 关于这个主题有一篇很好的文章: 您可能错误地存储了密码

为了更广泛地回复,我同意以上所有内容,哈希使它更容易 理论上 获取用户的密码,因为多个密码匹配相同的哈希值。但是,这比访问您的数据库的人的可能性要小得多。

事实上,如果你对某些东西进行哈希处理,是的,就会发生冲突,因此两个不同的密码可能会解锁同一个帐户。

但从实际的角度来看,这是一个糟糕的论点 - 一个好的散列函数(md5 或 sha1 就可以)几乎可以保证对于所有有意义的字符串,尤其是短字符串,不会发生冲突。即使有,一个帐户有两个密码匹配也不是一个大问题 - 如果有人能够足够快地随机猜测密码以至于他们很可能能够进入,那么你就会遇到更大的问题。

我认为,以纯文本形式存储密码比密码匹配中的哈希冲突存在更大的安全风险。

我不是安全专家,但我有一种感觉,如果纯文本更安全,那么哈希值从一开始就不会存在。

理论上是的。密码可能比哈希值更长(更多信息),因此存在哈希冲突的可能性。然而,大多数攻击都是基于字典的,并且冲突的概率比成功的直接匹配小得多。

这取决于你要防御的是什么。如果攻击者拉下了您的数据库(或欺骗您的应用程序显示数据库),那么明文密码就没用了。有许多攻击依赖于说服应用程序泄露其私有数据——SQL 注入、会话劫持等。通常最好根本不保留数据,而是保留散列版本,这样坏人就无法轻易使用它。

正如您的同事所建议的,通过对字典运行相同的哈希算法并使用彩虹表提取信息,可以轻松地解决这个问题。通常的解决方案是使用秘密盐加上额外的用户信息来使散列结果唯一 - 类似于:

String hashedPass=CryptUtils.MD5("alsdl;ksahglhkjfsdkjhkjhkfsdlsdf" + user.getCreateDate().toString() +  user.getPassword);

只要你的盐是秘密的,或者你的攻击者不知道用户记录的精确创建日期,字典攻击就会失败——即使他们能够拉取密码字段。

没有什么比存储纯文本密码更不安全的了。如果您使用良好的哈希算法(至少是 SHA-256,但即使 SHA-1 也比没有好),那么是的,冲突是可能的,但这并不重要,因为给定一个哈希值,不可能*计算什么字符串散列到它。如果您使用密码对用户名进行哈希处理,那么这种可能性也就不存在了。

* - 技术上并非不可能,但“计算上不可行”

如果用户名是“graeme”,密码是“stackoverflow”,则创建一个字符串“graeme-stackoverflow-1234”,其中1234是一个随机数,然后对其进行散列并存储“哈希输出1234”在数据库中。在验证密码时,获取用户名、提供的密码和存储值末尾的数字(散列具有固定长度,因此您始终可以这样做)并将它们散列在一起,并将其与散列进行比较存储值的一部分。

更多的密码可以匹配哈希,字典/哈希攻击会更快。

是和不是。使用现代哈希算法(例如 SHA 变体),这个争论就会变得非常非常无力。如果暴力攻击只需要 352 年而不是 467 年,你真的需要担心吗?(这是一个轶事笑话。)所获得的价值(无需在系统上以纯文本形式存储密码)远远超出了您同事的担忧。

希望您原谅我插入我为此编写的解决方案,在传输密码之前使用客户端 JavaScript 对密码进行哈希处理: http://blog.asgeirnilsen.com/2005/11/password-authentication-without.html

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top