[技术分享]20120118用户密码安全存储建议
安全小测验:存储机密信息最安全的办法是什么?
a) 利用 256 位密钥的强对称加密算法(例如 AES)进行加密。
b) 利用 4096 位密钥的非对称强加密算法(例如 RSA)进行加密。
c) 利用平台内置的加密系统进行加密,例如 Windows 的数据保护 API (DPAPI)。
做出选择了吗?正确的答案实际上是:
d) 既然是机密数据,就完全不要存储!
好吧,这个问题看上去有点难,但其答案是很有道理的:窃贼无法窃取根本不存在的东西。我们把这个原则应用到身份验证操作,如网站登录。如果一个网站永远不存储用户的密码,那么即使网站受到攻击,这些密码也不能被盗走。但是网站如何在不存储用户密码的情况下来验证用户的身份呢?答案就是网站存储密码的加密哈希,而不是明文密码本身。(如果你对哈希的概念不熟悉,我们建议你在继续前阅读 https://msdn.microsoft.com/zh-cn/library/92f9ye3s.aspx#hash_values。)通过比较哈希而不是明文,网站仍然可以验证用户确实知道自己的密码,不然哈希将不会匹配,而实现这个过程并不需要网站实际存储密码(如图1所示)。这是一个不错的解决方案,但是仍有一些设计方面的注意事项,以确保你不会无意间削弱系统的强度。
第一个设计问题是,简单地对密码进行哈希计算并不能提供充分的保护:你还需要在计算哈希值前为每个密码添加随机盐值(Salt)。切记,对于给定的哈希函数,对某个输入值计算哈希值始终会得到相同的输出值。如果时间充裕,攻击者可能会计算出明文字符串及其相应哈希值的表。事实上,已经存在很多这样的表(称为“彩虹表”),并且可在互联网上免费下载。有了彩虹表后,如果攻击者通过任意方式设法获取了某网站的密码哈希列表,那么他可以使用该表轻松地确定初始的明文密码。当你对哈希加盐值时,你就可以从攻击者手中夺走这个“武器”。另外,要为每个用户生成(并存储)特定的盐值,而不是每个用户使用相同的盐值,这一点很重要。如果你始终使用相同的盐值,则攻击者可能会构建一个使用该单一盐值的彩虹表,从而提取出密码。
图 1:比较加盐值后的哈希值
另一个重要的设计问题是,一定要使用强加密哈希算法。MD5 可能是比较常见的选择,但是密码学家已经论证了 MD5 的脆弱性,近年来它一直被认为是不安全且“可破解”的算法。SHA-1 安全性稍微强一些,但它也开始显现被破解的迹象,现在密码学家建议避免使用 SHA-1。SHA-2 哈希算法系列当前被视为最强健的算法,是唯一获得微软安全开发生命周期 (SDL) 加密标准策略批准,可以在微软 产品中使用的哈希算法系列。
相比将SHA-2硬编码入程序,一个更好的办法是实施 “加密灵活性”,就是说即使应用程序已经部署到生产中,也仍然可以改变哈希算法。毕竟,加密算法会过时;密码学家会发现其弱点,并且随着计算能力的增强,使用暴力攻击破解越来越轻松可行。某一天,SHA-2 可能会被认为和 MD5 一样脆弱,未雨绸缪不失为明智的选择。对哈希灵活性进行深入分析讨论已经超出了本篇博文的讨论范围,不过,你可以在 MSDN 杂志文章“加密灵活性”[ https://msdn.microsoft.com/zh-cn/magazine/ee321570.aspx] 中阅读了解关于建议解决办法的更多信息。就像 SDL 强制在微软 产品中使用强加密算法一样,它也鼓励产品团队尽可能使用加密灵活性,这样可以在当前强算法遭到破解的情况下更敏捷地迁移到新算法。
到目前为止,我们已经讨论了要对 哪些内容 进行哈希计算(密码和随机的特定盐值)以及 如何 进行哈希计算(使用 SHA-2 系列中的加密强哈希算法,最好是可配置的,以便允许进行未来变更),但是我们还没有讨论哈希计算的 应用位置 。你可能会认为在客户端执行哈希计算将能极大地提高安全性,因为你只需要通过网络向服务器发送哈希,而绝不会发送明文密码本身。不过,好处也并不像你想象的那么多。如果攻击者能够嗅探网络流量,他仍然可以拦截传输,并自行将哈希传递到服务器,从而欺骗用户,劫持其会话。这时,哈希本质上会成为明文密码。这个方法唯一切实的好处就是如果受害者在多个网站上使用同一密码,则攻击者将不能在其它网站损害受害者的帐户,因为知道密码的哈希值并不会告诉你关于密码本身的任何内容。防御此类攻击的更好方式是,在服务器端执行哈希计算,但确保密码和所有凭据令牌(例如会话 Cookie)始终通过 SSL/TLS 进行传输。在将来发布的博文中,我们会讨论安全凭据传输(和密码管理的其他方面,例如密码复杂性及其过期时间)。
遵循下面一些简单的原则,有助于你确保应用程序的用户凭据仍保持安全,即便在数据库被攻破的情况下也是如此:
· 始终存储并比较密码的哈希,而永远不要存储明文密码本身。
· 在进行哈希计算前,对每个密码应用随机且特定的盐值。
· 使用加密的强哈希算法,例如 SHA-2 系列之一。
· 通过实施灵活的加密设计,允许未来潜在的算法变更。
· 对服务器层进行哈希计算,并确保通过 HTTPS 传输所有密码和凭据令牌。
资深安全项目经理
微软 SDL(安全开发生命周期)团队