如何安全地存储密码



不管是开发App仍是网站,只要有用户登陆环节,就会牵涉到如何存储用户的密码的问题。若是采用的存储密码的技术不够安全,一旦黑客闯入存储密码的数据库,他就能获取用户的密码从而可能给用户带来重大损失。这种情形任何公司都不但愿发生在本身身上,所以选择安全地存储密码的策略显得十分必要。html

不必定非要本身存储用户的密码

最简单的存储密码的方式就是本身并不存储,而是委托给信任的第三方存储。这就是OpenID技术,它的理念是用第三方来完成用户验证的操做。目前国外的网站如谷歌、雅虎等,国内的如腾讯等都已经提供OpenID的服务。若是咱们开发一个网站并选择谷歌的OpenID服务,那么用户就能够用Gmail的帐号和密码登陆,接下来用户认证的事情将由谷歌完成。程序员

采用OpenID技术不管是对网站的开发者仍是用户,就具有明显的优势。因为用户的登陆认证是由第三方的OpenID服务提供商完成的,咱们本身没有必要存储用户名和密码,也就没有必要考虑存储密码的安全性问题,从而减小开发的成本。同时,用户不用在咱们的网站上注册新的用户名和密码。这样既免去了用户在注册用户名和密码时填写资料的麻烦,也减去了用户须要记住一对新的用户名和密码的负担。算法

千万不要用明文存储密码

有不少公司因为种种缘由不肯意把本身客户的登陆信息保存在其余公司,因而不得不本身存储用户的密码。既然决定本身存储,就要考虑存储的安全性。密码存储的最低要求是不能用明文(没有通过加密)存储密码。若是用明文存储密码,一旦数据库泄露出去,全部用户的密码就毫无保留地暴露在黑客的面前,这可能给用户以及公司带来巨大的损失。数据库

虽然不能用明文存储密码的道理显而易见,但实际上仍然有很多公司在采用这种极度不安全的方式。这一点从时不时爆出的各类网站密码泄露事件能够看出。对那些仍然在用明文存储密码的公司,咱们只能奉劝他们尽早用哈希算法给密码加密以后再存储,别等到密码泄露以后形成重大损失才幡然大悟。安全

用哈希算法加密密码

经常使用的给密码加密的算法是几种单向的哈希算法。所谓的单向的算法是指咱们只能从明文生成一个对应的哈希值,却不能反过来根据哈希值获得对应的明文。常常被你们用来加密的算法有MD5SHA系列(如SHA1SHA256SHA384SHA512等)。值得注意的是,MD5算法已经被中国数学家王小云破解,所以这种算法已经不建议在产品中使用。网络

虽然用哈希算法能提升密码存储的安全性,但仍是不够安全。一般黑客在侵入保存密码的数据库以后,他会随机猜想一个密码,用哈希算法生成一个哈希值。若是该哈希值在数据库中存在,那么他就猜对了一个用户的密码。若是没有猜中也没有关系,他能够再次随机猜想下一个密码进行尝试。事实上黑客为了提升破解密码的效率,他们会事先计算大量密码对应的各类哈希算法的哈希值,并把密码及对应的哈希值存入一个表格中(这种表格一般被称为彩虹表)。在破解密码时只须要到事先准备的彩虹表里匹配便可。所以如今黑客们破解仅仅只用哈希算法加密过的密码事实上已经是不费吹灰之力。网站

加盐提升安全性

为了应对黑客们用彩虹表破解密码,咱们能够先往明文密码加盐,而后再对加盐以后的密码用哈希算法加密。所谓的盐是一个随机的字符串,往明文密码里加盐就是把明文密码和一个随机的字符串拼接在一块儿。因为盐在密码校验的时候还要用到,所以一般盐和密码的哈希值是存储在一块儿的。云计算

采用加盐的哈希算法对密码加密,有一点值得注意。咱们要确保要往每一个密码里添加随机的惟一的盐,而不是让全部密码共享同样的盐。若是全部密码共享统一的盐,当黑客猜出了这个盐以后,他就能够针对这个盐生成一个彩虹表,再将咱们加盐以后的哈希值到他的新彩虹表里去匹配就能够破解密码了。加密

虽然加盐的算法能有效应对彩虹表的破解法,但它的安全级别并不高,这是因为哈希算法的特性形成的。哈希算法最初是用来确保网络传输数据时的数据完整性。当咱们经过网络传输一个数据包时,咱们在发送时会在数据包的末尾附上这个数据包对应的哈希值。在接收数据时,咱们再次根据接收到的数据包用一样的算法生成一个哈希值。若是这个哈希值和从网络上接收到的哈希值同样,那就证实了数据在传输时没有出现问题。为了减小网络传输的延时,咱们但愿哈希算法尽可能的快,尽量地减小数据校验的时间。所以在设计哈希算法的时候,快速高效是一个很是重要的指标。目前在普通配置的电脑上,主流的哈希算法的耗时在微秒的级别,这意味着咱们能够在一秒之类计算哈希值近百万次。spa

快速高效的哈希算法给加密算法带来了很多的挑战,由于安全的加密算法应该是黑客极难破解的算法,而计算哈希值的耗时很是短,黑客们就能够用暴力法去破解加盐以后的用哈希算法加密的密码。前面提到,盐一般和哈希值存储在一块儿。因而黑客针对每个盐能够采用两种简单的暴力法破解密码。

一是采用穷举法。黑客生成一个密码,和盐拼接在一块儿再计算哈希值。若是哈希值和数据库中的哈希值一致,那么这个密码就被破解。若是不一致,在进行下一次尝试。这种方法对低级别的密码很是有效。好比6位全是数字的密码总共只有一百万中可能。这意味着任何6位的纯数字密码即便加盐以后也能在数秒以内破解。虽然用暴力法破解高级别的密码(好比同时包含数字、大小写字母和特殊符号的密码)目前还须要大量的时间,但计算能力遵循着摩尔定律持续地提升,今天看来很是耗时的操做在从此可能很是快速地完成。另外,近年来云计算的快速发展,也使得黑客们可以用很是便宜的价格租到大量的计算机以方便他们并行地破解密码,从而黑客们低成本而且高效地破解高级别密码成为了可能。

二是黑客们从历次密码泄露事件中收集了大量的经常使用密码。针对每个盐,黑客能够循环地从这些重用密码里挑选一个,加盐再计算哈希值。所以这些经常使用的密码即便加盐也很容易破解。

BCrypt或者PBKDF2增长破解的难度

为了应对暴力破解法,咱们须要很是耗时的而不是很是高效的哈希算法。BCrypt算法应运而生。咱们能够用BCrypt算法加盐以后给密码生成一个哈希值。Bcrypt最大的特色是咱们能够经过参数设置重复计算的次数。显而易见重复计算的次数越多耗时越长。若是计算一个哈希值须要耗时1秒甚至更多,那么黑客们采用暴利法破解密码将再也不可能。之前面提到的6位纯数字密码为例,破解一个密码须要耗时11.5天,更不要说高安全级别的密码了。

目前已有开源项目(http://bcrypt.sourceforge.net/)实现了BCrypt算法并被业界普遍采用。若是你是一个.NET程序员,你可能会发现目前的.NETFramework中尚未包含BCrypt的实现。此时有两个选择。一是已经有一些开源项目用C#实现了BCrypt算法,咱们能够直接使用。若是对这些实现的安全性存在担心,咱们也能够选择和BCrypt相似的PBKDF2PBKDF2一样也能够经过参数设定重复计算的次数从而延长计算时间。在.NETFramework中,类型Rfc2898DeriveBytes实现了PBKDF2的功能。

小结

安全地存储密码不是一件容易的事情。虽然目前有不少公司采用加盐的哈希算法应对彩虹表破解法,但这种方法并非足够安全的。因为哈希算法很是高效,计算哈希值耗时在微秒级别,所以黑客能够经过暴力法破解密码。一个推荐的办法用BCrypt或者PBKDF2延长计算哈希值的时间,从而提升破解密码的难度。另外,并非每一个公司、项目都须要本身存储密码。咱们的另外一个选择是用OpenID把用户校验工做委托给能够信赖的第三方公司。

原文地址:https://blog.csdn.net/cadcisdhht/article/details/19282407