如何打造更安全的密码

这几年来,密码的安全问题越来越严重,各家IT公司各出其法力求用户的密码更安全。要求用户输入的密码不能是有意义的英文组合,数字不能有规律,密码要求越复杂,最终用户自己都无法记住自己的密码了。对于各类的密码安全建议在网上有着不少的文章,本文主要讨论的是:如何避免暴力破解,如果认证的数据包被抓取到了,或者更严重的数据库密码泄露了的时候,我们是否能提前做一些措施能让我们的密码更安全,或者不要成为害群之马(例如保存了明文的导致用户习惯使用的密码完全公开)

不要使用明文

密码加密保存这已经成为常规(如果还是保存明文密码的,面壁吧),这不单单为了避免数据库泄露,还要防止内鬼操作。hash(password)这是最原始的做法,而网上有着大量算法的彩虹表,由于这种做法相同的密码生成出来的密码就很容易补破解了,因此现在较常用的是hash(hash(password) + salt)。至于salt的选择,如果所有用户使用相同的值,那么根据salt重新生成一次最常用密码的彩虹表也不是一件难事,因此salt也需要每个用户唯一。可以使用一个偷懒的方式是hash(hash(password) + account),最终选用怎样的方式,只要能保证每个用户不一致也就达到目的了。

密码认证过程再加盐

可能很多人认为,现在的网络慢慢转向https之后,数据包被抓取到的概率就会低了很多,但其实呢由于智能手机的普及,大量的小白用户去到哪,wifi连接到哪,而且很大可能信任了一些不知名的证书(国人对于IT安全的了解比我们想像中的还要低)。那么如果数据包被抓取了,如果保证密码的安全性呢?在验证过程中对密码再做一次加盐,每次验证生成的密码都是不相同的,避免可以使用相同的数据来达到登录的目的,验证的流程是调整为:

  • 服务器生成一个随机salt,保存到session中,返回到客户端

  • 客户根据hash(hash(hash(password) + account) + salt)生成密码,发送到服务器

  • 服务器根据用户提交的用户名,查数据库获取保存的密码(hash(hash(password) + account)),再根据session中的salt,生成hash(数据库保存的密码 + salt)与用户提交的数据对比是否一致,一致则用户登录成功,不一致则返回出错信息(无论是否一致,session中的salt都会被清除)

通过上面的方式调整之后,就算数据包被抓取到,也避免了使用同样的数据包做登录。

注:抓到数据包,如果使用的是cookie来保存认证token的,那么还是可以被冒认,对于这个的处理,也可以在登录的时候,把user-agent(或者一些特别的信息保存),发现不一致,提示警告用户或者直接删除登录session让用户重新登录等等,只能是尽量的多做安全检测。

密码认证慢响应

可能很多人觉得使用IP的次数限制是更合理的方式,但是在实际中发现,移动端的设备很多时候会共用出口IP,因此系统最终对于IP的频率限制的放得比较宽,很多时候效果并不好。

一般而言接口都是越快响应越好,但是对于密码的认证呢,就不可一概而论。为了避免通过暴力破解,一般对于密码的认证(登录)则选择合适的响应速度就可以(如果处理时间较短,则delay之后再响应)。

那么使用慢响应之后,是否是解决问题了呢?由于现在的机器都很强悍,一般而言,暴力破解的都会是多线程尝试,那么慢响应就会变得有点失效了,因此密码认证的过程中,如果有相同账号的认证正在处理中,则直接返回出错,避免被暴力破解(多次出现此种情况,系统做预警提示)。

使用slow hash

如果发生了最严重的情况,数据库泄露了或者内部人员从数据库中取到密码信息,那么这种情况怎么减少造成的影响呢?

我们来假设这样一种场景,内部人员取得了某个账户的资料,因为密码是加密的,不代表原始密码,那么怎么把这个从加密串得到原始密码的难度加大呢?

我们熟知的hash算法:MD5, SHA1, SHA256等等,在设计的时候,并没有考虑到slow hash的实现,对于现在的机器,根据现有的数据去生成彩虹表,使用的时间比我们想像中的还要快,为了加强密码的强度,我们建议使用slow hash,我所知道的slow hash只有bcrypt,而且我也没有实际的项目使用经验。大家可以根据自己的需要,上网搜索一下,选择对自己更合适的hash算法。

感言

对于安全上的设计,我自己了解的不多,考虑的也不够完善,实际上来说,没有绝对安全的方法,我们能做的只能是让整个过程变得更复杂,更少漏洞,增加破解的难度,简单来说就是让付出之后得到的回报不成正比就好,大部分事件都是利益驱动的。

Last updated