最近有朋友在使劲研究如何不使用 HTTPS 的状况下保护用户密码安全。暂且不说研究过程,但结论是要保障安全必须后端参与,使用非对称加密算法 —— 如此一来,不如直接用 HTTPS 更简单便捷有保障。使用免费 SSL 证书,一年一换,运维稍微麻烦一点,访问稍微慢一点(证书认证过程好像会慢一些),但至少是专业的,比本身研究的没通过大量检验的算法靠谱多了。前端
假设已经作过必要的安全防范,目前惟一须要解决的问题是保障用户密码在 HTTP 的明文传输过程当中不被窃取。为达此目的,研究过程以下:算法
若是说,密码在明文传输过程当中存在风险,最直接的解决办法是让密码再也不是原来的样子。使用一个 KEY
来加密密码,再将加密后的结果传输到后台,由后台解密使用。数据库
看起来确实起做用,若是窃取到加密后的密码数据,没有 KEY
是不能解密出来的。然而,KEY
要用于前端加密,就必定会存在于前端的某个地方,而前端的全部资源都是用户能够获取并分析的,甚至可使用浏览器的开发者工具经过各类调试手段来分析获取。因此 KEY
自己并不能安全保存,安全性被打破。segmentfault
此外,若是 secure_data
在传输过程被窃取,是能够重复使用的(由于 KEY
不变,加密结果就不会变),这也是一个不安全因素。后端
结论 📚使用对称加密算法来加密密码的方式不能保证密钥安全,也不能保证用户密码安全,更不能保护注册/登陆过程安全。浏览器
使用对称加密,在密文和密钥都被窃取的时候,能够解出密码原文,对用户在其余系统中(可能使用了相同密码)形成威胁。为此,咱们可使用不可逆的 HASH 算法来处理密码,只要先后端计算方式相同,不须要解密出密码原文,直接使用 HASH 结果就行。缓存
用户注册时,假设咱们有原密码 my_password
,使用 MD5 计算后是 a865a7e0ddbf35fa6f6a232e0893bea4
。这个 HASH 送到后端以后,后端是不能从 HASH 反算出原密码的,因此后端只能直接保存这个 HASH。安全
那么验证的时候,一样将原密码计算成 HASH a865a7e0ddbf35fa6f6a232e0893bea4
,传输到后端,后端拿它和保存的数据进行对比,相同则验证经过。服务器
有问题吗?固然有,你看 ——运维
使用 Hash 的过程
不使用 HASH 的过程
从传输过程开始,Hash 前的过程和 Hash 后的过程并无区别。对于偷窃者来讲,无所谓是拿到的 my_password
仍是 a865a7...
,只要把它送到后端,就能成功登陆。
因此这种作法并不能保护用户登陆!
不过密码是采用 Hash 计算过的,是否是能保护用户密码不会窃取用于尝试登陆其余系统呢?也不能!
一些常见的密码,好比 123456
采用 MD5 计算后是 e10adc3949ba59abbe56e057f20f883e
,拿这个 Hash 上百度就能查出来原密码是 123456
。固然,专业人士会有专业的工具,也就是彩虹表(什么是彩虹表?查查呗!),数以 TB 计的数据,可能大部分密码都查得出来吧。
结论 📚从前端对密码进行单纯的 HASH 算法,起不到任何保护做用。
其实从后端对密码进行单纯的 HASH 加密也只能起到很弱的保护做用,几近裸奔。
HMAC 比单纯的 HASH 算法,要多一个密钥因素,能够认为是加密的 HASH。使用 HMAC 能够有效的阻碍彩虹表破解。所以使用 HMAC 保护用户密码原文。可是,若是传输的是 HMAC 计算结果,和前面的讨论同理,并不能保护登陆。
但使用 HMAC 和单纯的 HASH 又有那么一点不一样。假设咱们已经经过其余方式进行安全的注册,后端已经保存了用户密码 my_password
,来看看下面这个登陆过程:
攻击者只须要窃取 hash_result
便可仿冒登陆,而 hmac_result
在传输过程当中能够轻松窃取。
此外,还有一个不安全点:固化在脚本中的 secure_key
是能够从拉到客户的脚本资源中分析出来的。
结论 📚使用固定 secure key 的 HMAC 算法并不能保障登陆安全,只能起到保密用户密码原文的做用。可是,因为
secure_key
很容易被拿到,因此对密码原文的保护也相对较弱。
继续寻找解决办法,咱们能够想到一个改进方案:若是知足下面两个条件,上面遇到的问题彷佛就能解决:
secure_key
并非固定在脚本中,而是动态产生的,就能够解决从脚本分析得到 secure_key
的问题;secure_key
使用 1 次后当即失效,那么 hmac_result
就不能用于再一次登陆,能够解决 hmac_result
被窃取复用的问题。动态 secure_key
看起来是个不错的办法,可是它应该在哪里动态产生呢?
若是在前端动态产生,就必须通知后端,传输的数据须要包含 secure_key
和 hmac_result
两部分。他们都能被窃取使用。这种状态下若是要保证 secure_key
只能使用一次,就必需要后端缓存全部用过的 secure_key
备查 —— 显然这会极大的增长后端负担。所以,不能够由前端来产生动态安全码。
用后端产生动态安全码以后能够当即缓存起来,同时传输给前端(这个过程能够前端发起请求)。前端按上述步骤对用户密码进行加密,将数据送回后端。后端检查 secure_key
在缓存中,取出来计算用于验证的 hmac_result
,同时从缓存中删除 secure_key
;若是 secure_key
不在缓存中,直接拒绝验证。
引入动态 secure_key
解决了登陆期间验证用户密码的问题。
虽然数据在传输过程当中仍然能被窃取,可是被窃取的数据不能重复使用,也不易破解出密码原文(可花长时间暴力破解),因此这个方案是初步可行的 —— 但要注意,它可能会受中到中间人攻击。
此外,该方案是不完整的,由于它只能解决验证密码(登陆)的问题,不能解决保存密码(注册)的问题 —— 注意到后端是直接从数据库加载的 my_password
,这意味着在注册时须要传入密码原文或者可解密出密码原文的密文 —— 这在以前的研究中都还没找到办法。
结论 📚后端产生一次性使用的动态
secure_key
能够保障登陆安全,但不能解决注册安全。并且该方案须要注意防御中间人攻击。注意:须要后端参与
到目前为止,咱们总算找到一个前端登陆勉强可用的安全方案。接下来还要研究用户注册时该怎么办。
注册时须要传输可解密的密文,并且在前端不能找到可用于解密的密钥 —— 这个场景很是符合非对称加密的应用场景 —— 前端使用公钥加密,后端使用私钥解密,问题就能获得完美解决:
结论 📚使用非对称加密算法,能够保护用户密码安全,也能够保护登陆过程安全。可是要注意中间人攻击。
注意:须要后端参与
到此为止,咱们已经很是接近 HTTPS 了。HTTPS 主要就是采用的非对称加密算法来保证数据传输安全。为了防止中间人攻击还引入了公信机构(受信任的证书中心)。可是,这个安全过程的参与方,包括 HTTPS 使用的安全协议(SSL 和 TSL 等)、服务器、公信机构、用户本身等,均可能成为整个安全过程的短板。
做为专业保障 HTTP 传输安全的 HTTPS 协议都随时在曝漏洞,请问,你又哪里来的信心凭一已之力用本身的安全算法实现来代替 HTTPS?若是没有足够的能力,仍是安心用 HTTPS 吧!
请关注公众号边城客栈⇗
看完了先别走,点个赞 ⇓ 啊,赞扬 ⇘ 就更好啦!