[TOC]
首先,引用知乎用户黄慧鹏的一段话。](https://www.zhihu.com/people/huang-hui-peng)%E7%9A%84%E4%B8%80%E6%AE%B5%E8%AF%9D%E3%80%82)
加密的本质是对原有内容的混淆,目的是提高从表面结果反推达到目的的成本。在网页提交(其实所有的通信都有这个问题)密码这个问题上,需要有几个维度来保证安全,首先是切面的安全性,对于一次提交首先保护的是密码本身,从最早的Base64到MD5或是SHA都可以做到这一点,但是Base64是可逆的,对于密码本身的保护是很弱的,哈希算法解决了这个问题,将不同长度的数据转换成统一长度的大数字,而理论上这个数字对应无穷多解,但限于密码的输入有限制,其实是可逆的,所以从1次混淆的MD5变成了3次混淆的SHA,但是随着现代计算机技术的进步,逆运算的成本不断降低,人们不得已要使用更大的数字来提高这个难度,但是为了向成本和发展妥协,人们不得已使用统一的算法,在CS时代由于很难侵入到CS两端,所以相对的双方使用的算法是保密的,破解难度相对比较大,BS由于为了保证开放性,特别是js本身就是明文算法,所以其实只能说防君子不妨小人,所以就有了安全控件,控件的唯一目的是用2进制代码来隐藏加密的算法,不知道算法,也就很难破解原文。第二维度就是时间,如果密码一样加密结果也会一样,那么在不使用原文的情况下,可以使用加密过后的数据来模拟用户登录的动作也是可以的,所以纯粹对密码的加密其实不能解决这个问题,所以有了盐值,让同一个数据在不同情况下结果依旧不一致,但是盐值需要约定,总会被人找出规律,只是成本又高了点,所以还是不安全,这就引发了通讯安全的问题。所以出现了https使用非对称加密来保护数据通路上的安全,让通讯变得不可窥视。但是还有个东西叫木马,所以人们在输入上继续做文章,包括混淆输入,就是软键盘,好的控件不会把明文存在内存里,这很重要,以前的VB、Dephi密码控件都仅仅看不到,实际内存里面都是明文,很容易被病毒和木马利用,所以一般来说现在最安全的bs系统使用控件保护输入,隐藏自己的HASH算法,用HTTPS保护通讯。但是ssl都有漏洞被爆出,所以好的系统加上用户自己勤换密码才是保护自己的不二法则,不过,太累了,所以使用硬件ukey吧,成本稍高
cookie和session的安全性
1 用户密码存放于cookie,每次请求都带上。
安全性
密码存放在cookie中,非常不安全。即使对密码进行加密,但是其他人只要盗窃了cookie,就算他不知道密码,也可以使用加密后的密码进行登录。
2 用户信息存在session中,cookie中存放sessionid
安全性
很不安全,cookie被盗窃,拿到sessionid,就可以获得用户身份。
开始httponly后,虽然无法使用脚本盗窃cookie,但是请求的数据在传输过程中可能被截获,也会导致cookie被盗。
具体可以参考cookie和session泄露与防范
session放在url中传递,服务器使用url重写。
很不安全啊,不要用这种方式,发明这种方式的人简直脑子有坑啊。
cookie和session泄露与防范
sessionid固定问题
攻击者使用一些方法,让用户使用给定的sessionid进行登录,服务器就会把这个sessionid与会话绑定。攻击者就可以使用这个sessionid伪装用户。
不得不说,会出现这种问题,服务器的开发者是个弱智。客户端的用户信息非常不可靠,竟然还是用客户端传过来的sessionid绑定,你是有多懒?
解决:登录成功后,刷新sessionid。
除了sessionid外,添加其他验证标识
例如,ip,User-Agent, 服务器收到用户请求时,把额外标志放到session中,用户的下一次请求对额外标志与session中的额外标志进行对比,如果不一致,就弹出层让用户输入密码。
当然,这个方法并不是完全可靠的,如果用户在使用代理软件,那么ip随时可能变化。另外,在局域网中,多个用户对服务器来说使用同一个外网ip,那么局域网内的session盗窃是不能用这个方法防范的。
添加token
使用随机秘钥对sessionid进行加密,生成token, 这样身份标识就增加到了3个:sessionid User-Agent token。
但是既然盗窃者可以拿到sessionid,那么他就可以轻易的同样拿到user-agent 和 token,这样来看,token并没有为盗窃者增加难度。
所以,我们可以使用不同的方式来传输,sessionid放在cookie中,token放在get或者post参数中。
当然,这些手段,虽然看起来增加了一些安全性,然而,无法避免在传输过程中,请求被拦截,然后进行盗窃。
事实上,像前面这几种方法,就算你添加100个用户标识,也是然并卵,除了增加服务器负担,没有带来多少安全性的提升。
在http下,如何对用户登录密码进行加密
有人认为http下,在客户端对用户密码加密是多此一举,攻击者总是可以获得加密后的信息,进行重复登录。
其实不然,只需要在登录时,添加上一个随机码,就可以保存密码的安全。
登录前,服务器向客户端发送一个随机码,客户端,使用用户名,密码,随机码和其他信息,进行Hash加密,服务器收到请求后,从数据库去除用户信息,用同样方式进行hash加密,若相同,则验证通过,同时随机码失效。
攻击者即使获取到加密后的信息,也无法进行重复攻击,因为随机码已经失效。
其实不仅仅是随机码,随便一个可变的数据,都可以用户加密密码信息。比如时间戳。
这种方法可以保证http下密码的安全性,但是这仅仅对登录有用,其他的数据传输还是要靠sessionid来辨别用户身份,sessionid被盗,还是不安全。
想要真正的安全性,还是要靠HTTPS来保证。
或者使用token验证
用户在注册登录和身份验证中的安全性问题和处理方法
1 注册和登录时,密码在传输过程中不能是明文
2 防止攻击者拿到密文后,进行重放攻击
3 数据库保存密码不能是明文
总之,可以采取的方案如下:
1、服务器端,用户注册时,客户端提交(密码M+验证码N进行可逆的方法加密)=密文O,服务器端,保存有验证码N,故而,可以逆向运算获得密码M (随机码A) 和 (密码B+随机码A进行MD5加密)密文C。虽然密文O是可逆的运算,但是,在提交过程中是不包括验证码N的,加上比较独特的加密算法,基本可以保证安全了。
2、提交注册或登录信息时,客户端先从服务端获得随机码A,然后提交(随机码A) 和 MD5(MD5(密码B)+ 随机码A)=密文C,服务端组合后进行MD5加密,与数据库验证。
3 另外,可以采用类似https的方式,比如非对称加密 + 随机码(防重放)。
在http环境下,没有任何方法是安全,只能放君子不防小人,这些方法也只是增加破解的复杂度。