前端传输加密的意义和实现

6,450 阅读4分钟

最近因为做项目的原因,涉及到登录注册的密码安全问题,于是在网上搜了一圈,然后在知乎上看到一个很热的贴子。有说没意义的,也有说有意义的。

整体看下来,说无意义的,无非说是对于后端而言,前端直接发送明文密码,还是使用md5,decypt,sha等加密的密文密码,从数据层面来讲,都是『明文』,只要被劫持,就算是密文,也并不需要去破解,直接伪造请求,照样发送就好了。再加上,因为前端代码是运行在用户本地浏览器,什么加密算法都是用户可见的,混淆,散列,加密无非是增大这种可见的难道,根本上并没有解决问题。

说有意义的呢,更多说的是保护用户隐私,不至于明文在网络上传输,可以防止同密码跨站使用,不在后台日志明文记录,增加破解难度,防君子不防小人等等,总的来说,它的意义不在于鉴权。

但有一点好像是一致的,大体上两派都认为,前端加密传输在鉴权这块意义不大,而是应该通过https来做根本解决。

我在这也谈谈我实现思路。我们先假设一个前提,就是不管是https,还是http,数据在传输的过程中都有被劫持的可能。那我们要怎样去设计加密传输,从而保护用户的密码数据呢?或者说客观上只有http,没法上https,怎么最大可能去保护密码的安全性。

以下是实现过程,分为登录、注册和修改密码:

1,数据库里,我们以用户的username做为唯一键,密码使用最简单的md5(password)存储

2,用户登录时,待用户输入用户名后,前端带上这个username,请求后端的/user/login-salt接口。接口验证用户名存在后,生成一个临时的salt,保存到表里或缓存中,并设置一个较短的过期时间,然后返回给前端。

3,待用户输入完用户名和密码后,前端使用md5( md5( password ) + salt )将用户的密码加密,发送到后端的/user/login登录接口进行登录验证。如果验证成功,即表示登录成功,返回登录后的token,并删除这个临时的salt;如果验证失败,则生成一个新的salt替换,并返回给前端,用户重新输入,重新验证。

4,如果salt超时,直接跳过登录验证,重新生成替换并发送给前端。

5,以上即可以保证,每次发送的密码密文都是唯一的且只能使用一次,就算被劫持,拿到这个密码也无法再次登录。

6,上样的步骤,基本可以保证登录鉴权的安全性,但这里还是会有一个问题。那就是虽然登录解决了,但注册或修改密码是无法避免明文发送的,虽然注册、修改密码相对于登录操作要低频很多,但这仍是一个漏洞。我们怎么在这两个操作也使用密文呢?于是我想到了非对称加解密的RSA。

7,在注册和修改密码的时候,前端向后端申请一个公钥,或者直接通过config读取,利用公钥对用户的密码进行加密,传输到后端,后端使用私钥解密,得到明文密码,然后md5( password )保存到数据库即可。这样就算这个密文被劫持,它也无法直接拿去登录,再就是因为rsa的特性,就算劫持者拿到了公钥和密文,也基本无法算出密码的明文。从而可以保证密码在注册和修改时的安全性。

至此,基本上完成了在非安全网络环境下,用户密码的密文传输和实现。当然这的md5可以选用更可靠的sha替代,密码存储也可以使用固定salt+password的方式存储到库中,这些都是更细节的优化了,不在此文讨论。