近期在实现HTTP和SIP DIGEST认证,对用户登录时密码的传输与存储问题有了疑问与思考。
根据之前的开发经验,密码肯定是不能直接明文存储在数据库中的,一旦数据库被攻破,不仅本网站的用户信息面临危险,根据用户设置密码的惯性,可能会导致用户很多关联网站的信息也被窃取。为此常用的做法就是使用SALT + HASH的方法,至于HASH算法的话常用的就是MD5/SHA256/SHA512,但是当使用DIGEST认证时,问题就出现了:
DIGEST认证主要是采用服务器端和客户端生成的随机码以及一些额外信息和密码做MD5摘要,最终由终端生成response,传递到服务器,服务器再同样根据随机码等信息以及密码进行MD5摘要,和客户端生成结果进行比较,从而完成密码校验(详情可参照RFC 2617)。
根据上面的描述,也许有人已经想到,关键问题就是:服务器完成DIGEST认证时需要与客户端的密码一致。但是如果服务端不存明文密码,而是采用SALT+HASH的方式存储密码,该如何实现呢?初步的解决思路有两个:
1. 将SALT通知客户端,客户端采用相同的HASH算法进行密码摘要后,使用结果作为DIGEST认证的密码,在进行DIGEST RESPONSE计算。
2. 服务器不使用不可逆的HASH算法存储密码,而是采用对称加密的方式,对称加密密钥随机生成,并与用户名、密码分表或分库存储,从而保证安全性。
个人选择方法2,下面谈一谈方法一的缺陷
-- 将存储密钥用的SALT通知到客户端本身就是很不安全的行为,如SALT被截获就大大增加了别人破解密码的可能性
-- 其次,由于这次做的产品本身属于标准化产品,登陆过程需支持标准DIGEST方式,无法限制其他客户端的行为,如采用此方式,必然在标准化测试与对接时面临问题。
为此权衡再三,还是觉得使用方法2较为可靠一些,不知各位有没有什么别的好想法?
其实就协议来看,DIGEST认证本身就不是太安全,也很容通过字典攻击等常见MD5破解方式完成密码破解。为此为保证传输密码安全,还是需要使用TLS。
PS: 其实DIGEST认证个人感觉在HTTP协议中用途并不广,有印象的只有以前路由器的登陆使用了该方式,SIP中DIGEST登陆貌似倒是挺多的,但好像也逐渐被AKA认证所取代,后续还是有必要分析一下SIP AKA和HTTP中的密码传输与存储问题进一步研究一番。