日期:2014-05-18  浏览次数:20436 次

讨论:一种更好的登录验证和密码保存算法
对于防止黑客攻击,没有最安全的方法,只有更安全的方法,web的登录验证机制的安全性其实还是很脆弱的,但我们可以不断改进。

目前我们的项目中存在的一个大问题是:我们将用对称加密(DES)加密过的用户名写到了cookie中去以便记录用户的登录状态,这样可能产生较大的隐患:

一是只要能够截获一个用户的http报文,即可冒充这个用户来使用我们的系统 

二是一旦知道我们的加密方法(比如利用网站的其它漏洞或其它途径获取了我们的源码)就能随意伪造登录信息实现无任何限制的操作

目前考虑改进,达到以下的安全目标:

Cookie的登录信息是加密的,不可逆转的,即便攻击者获取了我们的源码,他也不能反向获取到明文用户信息(如果不需要长期保存登录状态,可以考虑不在cookie中存放任何用户信息,只存放Token) 

Cookie的登录信息是无法伪造的,即便攻击者获取了我们的源码,但由于攻击者不能访问我们的数据库,他仍然无法伪造登录Cookie 

如果Cookie的登录信息是通过截获http报文伪造的,我们能够识别(可能需要根据IP地址和端口等额外信息) 



------解决方案--------------------
https或者隐式的SSL
通信签名,根本不能被篡改。
这样的cookie已经很安全了。除非客户机出现安全问题。

然而责任,不就是用来推的么。
------解决方案--------------------
1)在cookie中,保存三个东西——用户名,登录序列,登录token。

用户名:明文存放。
登录序列:一个被MD5散列过的随机数,仅当强制用户输入口令时更新(如:用户修改了口令)。
登录token:一个被MD5散列过的随机数,仅一个登录session内有效,新的登录session会更新它。

2)上述三个东西会存在服务器上,服务器的验证用户需要验证客户端cookie里的这三个事。

3)这样的设计会有什么样的效果,会有下面的效果,

a)登录token是单实例登录。意思就是一个用户只能有一个登录实例。

b)登录序列是用来做盗用行为检测的。如果用户的cookie被盗后,盗用者使用这个cookie访问网站时,我们的系统是以为是合法用户,然后更新“登录token”,而真正的用户回来访问时,系统发现只有“用户名”和“登录序列”相同,但是“登录token” 不对,这样的话,系统就知道,这个用户可能出现了被盗用的情况,于是,系统可以清除并更改登录序列 和 登录token,这样就可以令所有的cookie失效,并要求用户输入口令。并给警告用户系统安全。

4)当然,上述这样的设计还是会有一些问题,比如:同一用户的不同设备登录,甚至在同一个设备上使用不同的浏览器保登录。一个设备会让另一个设备的登录token和登录序列失效,从而让其它设备和浏览器需要重新登录,并会造成cookie被盗用的假象。所以,你在服务器服还需要考虑- IP 地址,

a) 如果以口令方式登录,我们无需更新服务器的“登录序列”和 “登录token”(但需要更新cookie)。因为我们认为口令只有真正的用户知道。

b) 如果 IP相同 ,那么,我们无需更新服务器的“登录序列”和 “登录token”(但需要更新cookie)。因为我们认为是同一用户有同一IP(当然,同一个局域网里也有同一IP,但我们认为这个局域网是用户可以控制的。网吧内并不推荐使用这一功能)。

c) 如果 (IP不同 && 没有用口令登录),那么,“登录token” 就会在多个IP间发生变化(登录token在两个或多个ip间被来来回回的变换),当在一定时间内达到一定次数后,系统才会真正觉得被盗用的可能性很高,此时系统在后台清除“登录序列”和“登录token“,让Cookie失效,强制用户输入口令(或是要求用户更改口令),以保证多台设备上的cookie一致。
------解决方案--------------------

session+cookies

如果是后台登陆操作。。。可以加上IP白名单。。。

只允许某几个IP去登陆后台。。。
------解决方案--------------------
如果你不想做https的话,报文截取这个漏洞永远无法避开啊。伪造http报头不是很容易的事。
只有人工模拟https的访问机制了。

客户器端维护一个内存表theT
guid
token
cookie_private_key
session_begintime

1)用户访问网站 

session_onstar 中给出一对会话公密钥。
公钥写cookie中cookit["session_public_key"] 
私钥放session中 session["session_private_key"]
当前时间放入sesison中的session["session_beginTime"].
theT中新加一条
theGuidString = new guid().tostring();
theTokenString = new guid().tostring();
theGuidString ,theTokenString ,session["session_private_key"],session["session_beginTime"]
session["theGuidString"]=theGuidString;
session["theTokenString"]=theTokenString;

2)用户被重定向到 cookielogin.aspx

3) cookielogin.aspx中用js打开cookie["public_key"],用RSA算法解密cookie["token"],得到的明文token使用cookit["session_public_key"]加密,提交到"cookielogincheck.aspx?guid=" +cookie["guid"] + "&token=" + cookie["token"]。

4)cookielogincheck.aspx中
取得guid,和token
在theT中查到cookie_private_key(查不到跳到输入用户名密码登录页)
将cookie["token"]用session_private_key解密后得到的token原文与theT中得到的token对比。确定是否是上一次成功登录的用户。(查不到跳到输入用户名密码登录页)

删除原cookie["guid"]对应的theT记录

更新cookie["guid"]为session["theGuidString"]

更新cookie["token"]为session["theGuidString"]使用session["session_private_key"]加密后的串

更新cookie["public_key"] = session["session_public_key"]

5)定时根据session_begintime清除theT中过期的记录。

这样不同的session用同一个cookie也没有办法了。

------解决方案--------------------