我们目前正在为我们拥有的网络应用程序存储纯文本密码。
我一直提倡使用密码散列,但另一位开发人员说这会不太安全——更多的密码可以匹配散列,字典/散列攻击会更快。
这个论点有任何道理吗?
我们目前正在为我们拥有的网络应用程序存储纯文本密码。
我一直提倡使用密码散列,但另一位开发人员说这会不太安全——更多的密码可以匹配散列,字典/散列攻击会更快。
这个论点有任何道理吗?
绝对没有。但这没关系。我之前也发过类似的回复:
不幸的是,人们,甚至是程序员,都太情绪化了,不容易被争论所左右。一旦他投资于他的职位(而且,如果你在这里发帖,他就是)你不可能仅凭事实说服他。你需要做的是转换举证责任。你需要让他出去寻找他希望能说服你的数据,并在这样做的过程中了解真相。不幸的是,他有现状的好处,所以你有一条艰难的道路。
来自维基百科
一些计算机系统将用户密码存储为明文,用于比较用户登录尝试。如果攻击者获得对此类内部密码存储的访问权限,则所有密码以及所有用户帐户都将受到威胁。如果某些用户对不同系统上的帐户使用相同的密码,那么这些帐户也会受到损害。
更安全的系统以加密保护的形式存储每个密码,因此对于获得系统内部访问权限的窥探者来说,访问实际密码仍然很困难,同时验证用户访问尝试仍然是可能的。
一种常见的方法仅存储明文密码的“散列”形式。当用户在这样的系统上输入密码时,密码处理软件会运行加密散列算法,如果用户输入生成的散列值与密码数据库中存储的散列值匹配,则允许用户访问。哈希值是通过将加密哈希函数应用于由提交的密码和通常称为盐的另一个值组成的字符串来创建的。salt 可防止攻击者为常用密码构建哈希值列表。MD5 和 SHA1 是常用的加密散列函数。
您可以在该页面上阅读有关该主题的更多内容。在我看来,在我阅读和使用的所有内容中,散列是一个更好的方案,除非您使用非常小的(< 256 位)算法。
绝对没有理由在 Web 应用程序上保留纯文本密码。使用带有盐值的标准散列算法(SHA-1,而不是 MD5!),这样彩虹攻击就不可能了。
如果你不加盐你的密码,你怀疑彩虹表攻击(预编译字典对给定的哈希有有效的输入)
如果您以明文形式存储密码,则其他开发人员应该停止谈论安全性并开始阅读有关安全性的内容。
冲突是可能的,但对于密码应用程序来说通常不是一个大问题(它们主要是在使用哈希作为验证文件完整性的方式的领域中的问题)。
所以:给你的密码加盐(通过在密码的右侧添加盐*)并使用良好的散列算法,如 SHA-1,或者最好是 SHA-256 或 SHA-512。
PS:这里有更多关于哈希的细节。
*我有点不确定 Salt 应该放在字符串的开头还是结尾。问题是,如果您有冲突(具有相同哈希的两个输入),将 Salt 添加到“错误”一侧不会更改生成的哈希。无论如何,Rainbow Tables 不会有大问题,只有碰撞
我不明白您的其他开发人员如何“更多密码可以匹配哈希”。
有一种说法是“散列攻击会更快”,但前提是你没有在密码被散列时加盐。通常,散列函数允许您提供盐,这使得使用已知的散列表成为浪费时间。
就个人而言,我会说“不”。基于上述情况,以及如果您确实以某种方式获得了明文公开,那么加盐的散列值对于试图进入的人来说几乎没有价值。散列还提供了使所有密码“看起来”的好处相同的长度。
即,如果散列任何字符串总是产生 20 个字符的散列,那么如果您只需要查看散列,您就无法判断原始密码是 8 个字符还是 16 个字符。
我在工作场所遇到了同样的问题。为了让他相信散列更安全,我所做的就是编写一个 SQL 注入,从我们网站的公共部分返回用户和密码列表。它立即升级为一个主要的安全问题:)
为防止字典/哈希攻击,请务必针对每个用户唯一且静态的令牌进行哈希处理(用户名/加入日期/用户 GUID 效果很好)
关于程序员伪装成密码学家有句老话 :)
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 是一个随机数,然后对其进行哈希处理并将“ hashoutput 1234”存储在数据库中。在验证密码时,获取用户名、提供的密码和存储值末尾的数字(哈希具有固定长度,因此您始终可以这样做)并将它们哈希在一起,并将其与哈希进行比较部分储值。
更多的密码可以匹配散列,字典/散列攻击会更快。
是和不是。使用现代散列算法,如 SHA 变体,并且该论点变得非常非常周。如果暴力攻击只需要 352 年而不是 467 年,你真的需要担心吗?(那里的轶事笑话。)获得的价值(没有以纯文本形式存储在系统上的密码)远远超过了您同事的关注。
希望您原谅我插入我在此编写的解决方案,使用客户端 JavaScript 在传输密码之前对其进行哈希处理:http: //blog.asgeirnilsen.com/2005/11/password-authentication-without.html