我在做用户登陆时大费周章,又是rsa又是md5的,忽然想起DNS欺骗的问题,如果用户被dns劫持,不管我用什么样的方法,用户如果在被劫持的页面上输入密码都毫无安全可言,并且https我们是不可能用的,瞎将就吧,我只能寄希望于用户装了某管家或某卫士。
但是后面的问题更严重,大家都知道http依赖cookie保持会话状态,我们大费周章地用各种加密方式来保护用户密码,最后却转化成为十几二十个明文字符来标识用户身份。找个抓包工具来截获这串数据并不是难事,而想伪造cookie就更简单了,这就是说,如果你登陆成功,其它人就很可能和你"共享"这个帐号了,所以只依靠sessionID就完全信任用户发来的请求十分危险。
有如下解决方案:
步骤一:用户打开登陆页面,获得RSA公钥
步骤二:用户点击登陆时在浏览器生成一个随机串我们称之为key,将key保存在用户浏览器中(需要html5支持),此key将会是身份认证的关键
步骤三:浏览器将password和key分别使用RSA公钥加密并发送至服务器
步骤四:服务器解密password和key并将key缓存入session
步骤五:服务器返回一个随机串,存入cookie和session中(我们将此随机串称为nonceStr,其只可以作为下一次校验的签名参数之一)
至此为止只有发送key的浏览器和拥有RSA私钥的服务器知道key的具体内容,我们可以使用任意一种签名方式来验证请求的来源,这里给出一种类似微信的签名方式:
客户端收到nonceStr后
步骤六:将浏览器中的key和cookie中的nonceStr拼接成key=keyVal&nonceStr=nonceStrVal
步骤七:使用md5进行摘要,并使用hex进行编码得到sign,使用js将sign添加到cookie中
用户发送请求至服务器后,需要配置拦截器拦截所有需要校验的链接
步骤八:服务器端从session中取出key并从session中取出nonceStr(cookie中的nonceStr用户可伪造从而造成一个nonceStr和sign的组合顶替了原先sessionID的位置,所以服务端认证时不能从cookie中获取)重复上面第二到四步的签名过程
步骤九:将计算得出的sign与cookie中的sign对比完成校验
步骤十:如果校验成功服务器更新session中的nonceStr并将其放入cookie和session中准备好下一次校验
以上的方法还存在问题,如果你第一次发送的请求因为某些原因被拦截或没有成功,并且有人此时监听到你发送的cookie中的sign他便可以伪造一次请求,但此方法的好处是写一个js脚本引入即可一定程度上保证安全对页面几乎没有影响
如果安全要求比较高那么就只能对所有要提交的数据进行签名,但对前台代码的影响太大,而且对每个链接的所有参数签名并替换所有链接(有的ajax和图片src也需要签名)也不太现实。只能针对某些特定的链接使用