网络安全 频道

网页脚本“攻击-防范”全攻略

近来,网络上的SQL Injection
漏洞利用攻击,JS脚本,HTML脚本攻击似乎逾演逾烈。陆续的很多站点都被此类攻击所困扰,并非像主机漏洞那样可以当即修复,来自于WEB的攻击方式使我们在防范或者是修复上都带来了很大的不便。HOOO……
一个站长最大的痛苦莫过于此。自己的密码如何如何强壮却始终被攻击者得到,但如何才能做到真正意义上的安全呢?第一,别把密码和你的生活联系起来;第二,Supermaster的PWD最好只有你自己知道;第三,绝对要完善好你的网站程序。然而怎样才能完善,这将是我们此文的最终目的。
  安全防护,如何做到安全防护?想要防护就要知道对方是如何进行攻击。有很多文章都在写如何攻下某站点,其实其攻击的途径也不过是以下几种:
  1.
简单的脚本攻击
  此类攻击应该属于无聊捣乱吧。比如****:alert();
</table>等等,由于程序上过滤的不严密,使攻击者既得不到什么可用的,但又使的他可以进行捣乱的目的。以目前很多站点的免费服务,或者是自身站点的程序上也是有过滤不严密的问题。
  2. 危险的脚本攻击
  这类脚本攻击已经过度到可以窃取管理员或者是其他用户信息的程度上了。比如大家都知道的cookies窃取,利用脚本对客户端进行本地的写操作等等。
  3. Sql Injection 漏洞攻击
  可以说,这个攻击方式是从动网论坛和BBSXP开始的。利用SQL特殊字符过滤的不严密,而对数据库进行跨表查询的攻击。比如:
  [color=#693714]http://127.0.0.1/forum/showuser.asp?id=999[/color] and 1=1
  [color=#693714]http://127.0.0.1/forum/showuser.asp?id=999[/color] and 1=2
  [color=#693714]http://127.0.0.1/forum/showuser.asp?id=999[/color] and
0<>(select count(*) from admin)
  [color=#693714]http://127.0.0.1/forum/showuser.asp?id=999[/color]’; declare @a
sysname set @a='xp_'+ 'cmdshell' exec @a 'dir c:\'---&aid=9
  得到了管理员的密码也就意味着已经控制的整站,虽然不一定能得到主机的权限,但也为这一步做了很大的铺垫。类似的SQL
Injection攻击的方式方法很多,对不同的文件过滤不严密所采取的查询方式也不同。所以说想做好一个完整的字符过滤程序不下一凡功夫是不可能的。
  4.
远程注入攻击
  某站点的所谓的过滤只是在提交表格页上进行简单的JS过滤。对于一般的用户来说,你大可不必防范;对早有预谋的攻击者来说,这样的过滤似乎根本没作用。我们常说的POST攻击就是其中一例。通过远程提交非法的信息以达到攻击目的。
  通过上面的攻击方法的介绍,我们大致的了解了攻击者的攻击途径,下面我们就开始重点的介绍,如何有效的防范脚本攻击!
  让我们还是从最简单的开始:
  l 防范脚本攻击
  JS脚本
和HTML脚本攻击的防范其实很简单:server.HTMLEncode(Str)完事。当然你还不要大叫,怎么可能?你让我把全站类似<%=uid%>都加过滤我还不累死?为了方便的过滤,我们只需要将HTML脚本和JS脚本中的几个关键字符过滤掉就可以了:程序体(1)如下:
  ‘以下是过滤函数
  <%
  function CHK(fqyString)
  fqyString =
replace(fqyString, ">", ">")
  fqyString = replace(fqyString, "<", "<")
  fqyString = replace(fqyString, "&#", "&")
  fqyString =
Replace(fqyString, CHR(32), " ")
  fqyString = Replace(fqyString, CHR(9), "
")
  fqyString = Replace(fqyString, CHR(34), """)
  fqyString =
Replace(fqyString, CHR(39), "'")
  fqyString = Replace(fqyString, CHR(13),
"")
  fqyString = Replace(fqyString, CHR(10) & CHR(10), "</P><P> ")
  fqyString = Replace(fqyString, CHR(10), "<BR> ")
  CHK = fqyString
  end function
  %>
  ‘以下是应用实例
  <%=CHK(Username)%>
  Username=CHK(replace(request(“username”),”’”,””))
  使用Include把函数写在公有页面上,这样效率是最好的。
程序体(1)
  另外,值得我们注意的是,很多站点在用户注册,或者是用户资料修改的页面上也缺少脚本的过滤,或者是只在其中之一进行过滤,注册进入后修改资料仍然可以进行脚本攻击。对用户提交的数据进行检测和过滤,程序体(2)
如下:
  ‘以下是过滤函数
  If Instr(request("username"),"=")>0 or
  Instr(request("username"),"%")>0 or
  Instr(request("username"),chr(32))>0 or
  Instr(request("username"),"?")>0 or
  Instr(request("username"),"&")>0 or
  Instr(request("username"),";")>0 or
  Instr(request("username"),",")>0
or
  Instr(request("username"),"'")>0 or
  Instr(request("username"),"?")>0 or
  Instr(request("username"),chr(34))>0 or
  Instr(request("username"),chr(9))>0 or
  Instr(request("username"),"?K")>0 or
  Instr(request("username"),"[URL=http://hackbase.com/News/hk/#]$[/URL]")>0 or
  Instr(request("username"),">")>0 or
  Instr(request("username"),"<")>0 or
  Instr(request("username"),"""")>0 then
  response.write
"朋友,你的提交用户名含有非法字符,请更改,谢谢合作 <a href='****:window.history.go(-1);'>返回</a>"
  response.end
  end if
  程序体(2)
  为了提供工作效率我们再将过滤内容程序化,这样对多个参数的过滤效率将有很大程度上的提高:如
  程序体(3)
  ‘以下为程序主体
  dim Bword(18)
  Bword(0)="?"
  Bword(1)=";"
  Bword(2)=">"
  Bword(3)="<"
  Bword(4)="-"
  Bword(5)="’"
  Bword(6)="””"
  Bword(7)="&"
  Bword(8)="%"
  Bword(9)="[URL=http://hackbase.com/News/hk/#]$[/URL]"
  Bword(10)="'"
  Bword(11)=":"
  Bword(12)=" "
  Bword(13)="("
  Bword(14)=")"
  Bword(15)="--"
  Bword(16)="
chr(9)"
  Bword(17)=" chr(34)"
  Bword(18)=" chr(32)"
  errc=false
  ‘以下是应用实例部分
  for i= 0 to ubound(Bword)
  if
instr(FQYs,Bword(i))<>0 then
  errc=true
  end if
  next
  if
errc then
  response.write "<script language=""****"">"
  response.write
"parent.alert('很抱歉!您的操作违法了);"
  response.write "history,back();"
  response.write "</script>"
  response.end
  end if
程序体(3)
  有了上面的过滤函数您可以在任何需要过滤的地方应用过滤函数直接使用就可以了。这就使我们的修复工作大大的简化了。
  另外,我想在这里再次多提醒一下,一些站点的UBB在进行小的表情图标转化时也会出现过滤问题,由于很隐蔽所以不容易发现:
  如:
  我们标签内的文字进行修改,
  不知道各位看懂没,前一个单引号用来中和程序提供的左引号,第二个单引号用来中和闭合的右引号,这样程序输出就为:
  <img src=’img/0001.gif’ onerror=****:alert(); alt=’’>
  如果图片不存在,那么将激活onerror标签执行脚本程序。对于已经过滤了单引号的站点在这里用双引号一样可以完成。对于过滤了****字段的,只用alert()也完全可以。所以说要过滤就要过滤完全,别给攻击者留下一丝机会。
  防范SQL Injection 漏洞攻击
  可以这样说,这里似乎是整篇文章的重点了.SQL Injection
漏洞攻击的的多样化也使得我们在程序防护上不得不想的更多一些。面对SQL Injection 的强大”攻势”,我们到底该过滤哪些?
  一些常用的危险字符有
  '    数据库字段判别封闭
  --   某些数据库注释标志
  #   某些数据库注释标志
  "   可能导致程序出错
  \   跨越目录
  3221143836nicode  编码的特征字符
  [URL=http://hackbase.com/News/hk/#]$[/URL]  可能用于变量标注
  / 和\   一样
  NULL  
小心"空"录入的危险,可能导致数据库或系统处理报错,利用报错构造溢出.
  空格和'一起,构造sql injeciton
  ? =
&   如果存在二次参数传递,可能改写querystr。
  (1) 从最一般的.SQL Injection
漏洞攻击来看:用户名和密码上的过滤问题,如:
  提交:用户名为:’or’’=’ 用户密码为:’or’’=’
  从程序出发,我们完全可以得出,数据库在执行以下操作
  Sql=” SELECT * FROM lUsers WHERE
Username=''or''='' and Password = ''or''=''”
  这样一来,这样,SQL 服务器将返回 lUsers
表格中的所有记录,而 ASP 脚本将会因此而误认为攻击者的输入符合 lUsers
表格中的第一条记录,从而允许攻击者以该用户的名义登入网站。对此类注入的防范似乎简单的很:
  利用以下程序就可以实现,程序体(4)
  strUsername = Replace(Request.Form("Username"), "''", "''''")
  strPassword = Replace(Request.Form("Password"), "''", "''''")
  程序体(4)
  (2)杜绝SQL 注入式攻击的第一步就是采用各种安全手段监控来自 ASP request 对象
(Reques、Request.QueryString、Request.Form、Request.Cookies和
Request.ServerVariables) 的用户输入,以确保 SQL 指令的可靠性。具体的安全手段根据你的 DBMS 而异。
  SQL
注入式攻击可能引起的危害取决于该网站的软件环境和配置。当 Web
服务器以操作员(dbo)的身份访问数据库时,利用SQL注入式攻击就可能删除所有表格、创建新表格,等等。当服务器以超级用户 (sa)
的身份访问数据库时,利用SQL注入式攻击就可能控制整个 SQL 服务器;在某些配置下攻击者甚至可以自行创建用户帐号以完全操纵数据库所在的 Windows
服务器。
  如:
  [color=#693714]http://127.0.0.1/forum/showuser.asp?id=999[/color]’;declare @a
sysname set @a='xp_'+'cmdshell' exec @a 'dir c:\'--&aid=9
  [color=#693714]http://127.0.0.1/forum/showuser.asp?id=999[/color]’; declare @a
sysname set @a='xp'+'_cm’+’dshell' exec @a 'dir c:\'--&aid=9
  甚至可以执行像:net user fqy fqy /add
这样的指令.当然这就需要你当前的运行身份必须是Sa,或者你攻击的只是一台虚拟主机,我劝你还是就此打住.
  对于一些整机使用的站点来说防止通过80端口攻击而直接拿到整机管理权限,这一点就变得至关重要了。对xp_cmdshell
的过滤就成为首要,很多站点的程序都是用GET或者是GET与POST混合来提交数据的,对于此,我们给出一种防止GET进行SQL注入的程序:如
程序体(5)
  fqys=request.servervariables("query_string")
  dim nothis(18)
  nothis(0)="net user"
  nothis(1)="xp_cmdshell"
  nothis(2)="/add"
  nothis(3)="exec%20master.dbo.xp_cmdshell"
  nothis(4)="net localgroup
administrators"
  nothis(5)="select"
  nothis(6)="count"
  nothis(7)="asc"
  nothis(8)="char"
  nothis(9)="mid"
  nothis(10)="'"
  nothis(11)=":"
  nothis(12)=""""
  nothis(13)="insert"
  nothis(14)="delete"
  nothis(15)="drop"
  nothis(16)="truncate"
  nothis(17)="from"
  nothis(18)="%"
  errc=false
  for i= 0 to ubound(nothis)
  if
instr(FQYs,nothis(i))0 then
  errc=true
  end if
  next
  if errc then
  response.write ""
  response.end
  end if
  我要做点声明的是:以上的程序只是对GET方式提交的数据进行的过滤,千万不要盲目套用。
  像其他一些来自 ASP request 对象
(Reques、Request.QueryString、Request.Form、Request.Cookies和
Request.ServerVariables) 的用户输入的攻击方法的方法,大致都集中在脚本期望的输入变量是数字变量 (ID)
上,当然我们不能只看数字变量,比如:
  [color=#693714]http://127.0.0.1/systembbs/showtopic.asp?tid=99&name=abc[/color]'
and left(userpasswor d,1)='a
  [color=#693714]http://127.0.0.1/systembbs/addtopic.asp?tid=99&name=abc[/color]'
and userpasswor d=’or’’=’
  另外,如何单一的防止类似这样的注入错误?
  [color=#693714]http://127.0.0.1/systembbs/addtopic.asp?tid=99[/color]’ ;delete
forum_forum;--&page=33 防范程序: 程序体(6)
  ……addtopic.asp?action=add……
  ……addtopic.asp?action=delect……
  Action1=trim(Request.QueryString())
  if left(action1,7)"action=" then '限定querystring必须为 action=
  error(err01)'错误处理
  else
  action=Request.querystring("action")'取得querystring的值
  end if
  select case action'对querystring进行处理
  case "add"
  .....
  case "delete"
  ......
  case else '如果querystring没有这个值则进行错误处理
  error(err02)
  end select
  程序体(6)
  出现这样的攻击,使我们的站长们不得不又再次头痛,这里我可以给出大家一个解决最好办法,一般的来说,用户名长度字符数不会超过15个字符,大都为14字符。那么我们从长度出发,来进行过滤:如程序体(7)
  Name=replace(name,”’”,””)
  If len(name)>16 then
  Response.write “ 你要做什么?”
  Response.end
  End if
  程序体(7)
  为什么我们这里以及过滤了单引号,怎么还要再次取一个长度限制呢?不多说了,看看4ngel的文章先>
.别问我怎么转数字格式,我不会,嘿嘿…^_^!
  还继续回到我们的主题,” 脚本期望的输入变量是数字变量
(ID)”.怎样进行注入防范,天呐,方法太多了,最直接的就是判断是否是数字整型,还有一些比较个性的验证办法,我们一一介绍一下 如:程序体(8)
  一,判断数字是否是整型
  p_lngID = CLng(Request("ID"))
  二 取字长
这一点我相信一般的数据长度不会大于8位所以:
  If len(ID)>8 then
  response.write “bedpost”
  response end
  end if

我认为这是一种比较冒险的办法,就是再进行一次数据库的查询,如果数据库表内没有相同的值与之相同那么返回错误.
  sql = "SELECT NAME
FROM Category where ID="&ID
  set temp=conn.Execute(SQL)
  if
temp.bof or temp.eof then
  response.Redirect("index.asp")
  else
  cat_name=temp("name")
  end if
  set temp=nothing
  ‘上面的是数据ID
的检测,下面则是正式的查询
  sql = "SELECT ID T_ID, NAME FROM Category where
ID="&ID&" ORDER BY xh asc"
  rs.open sql,conn,1,1
  四,我自己常用的数据过滤脚本,专利,呵~
  id=replace(id,”’”,””)
  If len(
request(“id”))>8 then ‘ 为什么取长度上面程序中已经说明
  response.write ""
  response.end
  else
  If request(“id”)”” then
‘取不为空则是为了防止一些程序页中会出现空值情况,如果不在这里做判断,程序会校验出错.
  If
IsNumeric(request("id"))=False then ' 风清扬修改 ID数据监控程式
  response.write ""
  response.end
  end if
  end if
  end if
  程序体(8)
  由于我个人的编程习惯,我喜欢将所有的数据检验程序全部保留到整站的公用程序中,比如:conn.asp啦,只需要写一次就可以修复全站的问题.
  说到这里,我提一点关于攻击的问题,就是跑用户密码或者是用户名,一般常用的就是
  ….../show.asp?id=1 and
0<>(select count(*) from admin where id=3 and left(username,1)=’a’)
  这样去一个一个尝试,当然我们不能在这里提什么Perl程序去跑密码,程序是别人写,要自己知道原理.这里我只是想给个比较方便的办法就是取ASC码范围.这个要比单独跑要快很多.不论是是字母,数字,汉字,特殊字符,他们总会有对应的ASC码,用以下办法:
  ….../show.asp?id=1 and 0<>(select count(*) from admin where id=3 and
asc(right(left(usernamee,3),1)) between 1 and 10000)
  剩下的就随你了,一般的从97到122就可以啦,字母嘛,很快D.呵呵,有人想用mid 函数当然也是不错 asc(mid(username,2,1))
between 1 and 10000 也成.
  如何更加有效的防止SQL注入攻击?我们将在下面的文章中具体提到!
  l 防范远程注入攻击
  这类攻击在以前应该是比较常见的攻击方式,比如POST攻击,攻击者可以随便的改变要提交的数据值已达到攻击目的.又如:COOKIES
的伪造,这一点更值得引起程序编写者或站长的注意,不要使用COOKIES来做为用户验证的方式,否则你和把钥匙留给贼是同一个道理.
  比如:
  If trim(Request. cookies ("uname"))="fqy" and Request.cookies("upwd")
=”fqy#e3i5.com” then
  ……..more………
  End if
  我想各位站长或者是喜好写程序的朋友千万别出这类错误,真的是不可饶恕.伪造COOKIES
都多少年了,你还用这样的就不能怪别人跑你的密码.涉及到用户密码或者是用户登陆时,你最好使用session
它才是最安全的.如果要使用COOKIES就在你的COOKIES上多加一个信息,SessionID,它的随机值是64位的,要猜解它,不可能.例:
  if
not (rs.BOF or rs.eof) then
  login="true"
  Session("username"&sessionID) = Username
  Session("password"&
sessionID) = Password
  ‘Response.cookies(“username”)= Username
  ‘Response.cookies(“Password”)= Password
  下面我们来谈谈如何防范远程注入攻击,一般的攻击都是将单表提交文件拖到本地,将Form ACTION=”chk.asp”
指向你服务器中处理数据的文件即可.如果你全部的数据过滤都在单表页上,那么恭喜你,你将已经被脚本攻击了.
  怎么才能制止这样的远程攻击?好办,请看代码如下: 程序体(9)
  <%
  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
  response.write
"<br><br><center>"
  response.write " "
  response.write
"你提交的路径有误,禁止从站点外部提交数据请不要乱该参数!"
  response.write "
"
  response.end
  end if
  %>
  ‘个人感觉上面的代码过滤不是很好,有一些外部提交竟然还能堂堂正正的进来,于是再写一个.
  ‘这个是过滤效果很好,建议使用.
  if
instr(request.servervariables("http_referer"),"http://"&request.servervariables("host")
)
0
相关文章