从根源上切断SQL注入(限ASP)

来源:互联网 发布:上海淘宝美工培训 编辑:程序博客网 时间:2024/04/29 09:14

 之前发布在蓝色理想里的一个帖子.重新发在这里
最近看到论坛上好多朋友都在谈论asp+mssql的网站被注入问题.
本人所在公司旗下所有网站,前一阵也被人大规模扫描.再加上今年四五月份的时候曾经爆发过一次SQL注入攻击.所以一直在想,是不是又一次的大范围的攻击开始了呢.
今天把个人总结的对付SQL注入的方法给大家共享下.希望对大家有帮助.也欢迎大家来讨论,完善防范代码.
如何防范SQL注入是一个令人很头疼的问题,大家要明确一下.被注入的根本问题是程序写的不够严谨,如果你的判断足够严格,就绝对不会被注入.更不要期待使用一些组件,防火墙之类的来解决.使用这些东西,要么就是防范力度不够,要么就是与自己写的程序有冲突.本人最早的时候就用过网上的一段判断代码,直接加在conn里.但是后来使用过程中发现,使用编辑器编辑的内容,经常与判断代码冲突.
首先,要对付SQL注入,就要了解它的原理,如果连怎么被注入的都不知道,更何谈防范了.
        SQL注入,不论是get,post还是虚构cookie方式,从根本上说,都是通过执行SQL语句来实现的.
例如:"select * from TableName"
这种SQL语句是绝对不会存在注入点的. 只有包含接收参数的SQL语句才可能被注入.
如:
postid=request("id")
set rs=server.createobject("ADODB.recordset")
sql="select * from TableName where id="&postid
rs.open sql,conn,1,1
我只简单列一部分大家都会用到的代码.
这里的postid是在执行SQL语句之前被赋值的变量.如果未加任何防范措施,通过常用的and 1=1 和and 1=2 就可以测试出是否可以被注入.
不论你的SQL语句写的怎么复杂,都可以按照是否有条件参数来划分.

接着分析下网上常见的两种防SQL注入的方法
第一种是通过获取ServerVariables("QUERY_STRING")进行分析.然后针对分析结果作出不同的处理.
ServerVariables("QUERY_STRING")获取的是地址栏的字符,所以对post注入起不到防范作用
Dim Fy_Url,Fy_a,Fy_x,Fy_Cs(),Fy_Cl,Fy_Ts,Fy_Zx
'---定义部份 头------
Fy_Cl = 1 '处理方式:1=提示信息,2=转向页面,3=先提示再转向
Fy_Zx = "index.html" '出错时转向的页面
'---定义部份 尾------

On Error Resume Next
Fy_Url=Request.ServerVariables("QUERY_STRING")
Fy_a=split(Fy_Url,"&")
redim Fy_Cs(ubound(Fy_a))
On Error Resume Next
for Fy_x=0 to ubound(Fy_a)
Fy_Cs(Fy_x) = left(Fy_a(Fy_x),instr(Fy_a(Fy_x),"=")-1)
Next
For Fy_x=0 to ubound(Fy_Cs)
If Fy_Cs(Fy_x)<>"" Then
If Instr(LCase(Request(Fy_Cs(Fy_x))),"and")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"select")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"'")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"update")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"chr")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"delete%20from")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),";")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"insert")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"mid")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"master.")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"xp_cmdshell")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"exec%20master")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"net%20localgroup%20administrators")<>0or Instr(LCase(Request(Fy_Cs(Fy_x))),":")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"net%20user")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"%20or%20")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"truncate%20")<>0 orInstr(LCase(Request(Fy_Cs(Fy_x))),"master.")<>0 Then
Select Case Fy_Cl
Case "1"
Response.Write "<Script Language=JavaScript>alert(' 出现错误!参数"&Fy_Cs(Fy_x)&" 的值中包含非法字符串!/n/n请不要在参数中出现:and,select,update,insert,delete,chr等非法字符!/n/n我已经设置了不能SQL注入,请不要对我进行非法手段!');window.close();</Script>"
Case "2"
Response.Write "<Script Language=JavaScript>location.href='"&Fy_Zx&"'</Script>"
Case "3"
Response.Write "<Script Language=JavaScript>alert(' 出现错误!参数"&Fy_Cs(Fy_x)&"的值中包含非法字符串!/n/n请不要在参数中出现:,and,select,update,insert,delete,chr等非法字符!/n/n设计了门,非法侵入请离开,谢谢!');location.href='"&Fy_Zx&"';</Script>"
End Select
Response.End
End If
End If
Next
第二种方法是区分了post和get.通过request.form和request.querystring来判断
相信很多人在网站后台制作中都用到了编辑器.而编辑器中生成的内容经常包含单引,分号等特殊符号.这些特殊符号碰到过滤代码,就会被错认为成SQL注入行为

Dim Fy_Post,Fy_Get,Fy_In,Fy_Inf,Fy_Xh,Fy_db,Fy_dbstr
Fy_In = "'枫;枫and枫exec枫insert枫select枫delete枫update枫count枫*枫%枫chr枫mid枫master枫truncate枫char枫declare"
%>

<%
Fy_Inf = split(Fy_In,"枫")
'--------POST部份------------------
If Request.Form<>"" Then
For Each Fy_Post In Request.Form

For Fy_Xh=0 To Ubound(Fy_Inf)
If Instr(LCase(Request.Form(Fy_Post)),Fy_Inf(Fy_Xh))<>0 Then
Response.Write "<Script Language=JavaScript>alert('/n/n请不要在参数中包含非法字符尝试注入!');</Script>"
Response.Write "非法操作!系统做了如下记录↓<br>"
Response.Write "操作IP:"&Request.ServerVariables("REMOTE_ADDR")&"<br>"
Response.Write "操作时间:"&Now&"<br>"
Response.Write "操作页面:"&Request.ServerVariables("URL")&"<br>"
Response.Write "提交方式:POST<br>"
Response.Write "提交参数:"&Fy_Post&"<br>"
Response.Write "提交数据:"&Request.Form(Fy_Post)
Response.End
End If
Next

Next
End If
'----------------------------------

'--------GET部份-------------------
If Request.QueryString<>"" Then
For Each Fy_Get In Request.QueryString

For Fy_Xh=0 To Ubound(Fy_Inf)
If Instr(LCase(Request.QueryString(Fy_Get)),Fy_Inf(Fy_Xh))<>0 Then
Response.Write "<Script Language=JavaScript>alert('/n/n请不要在参数中包含非法字符尝试注入!/n/n ');</Script>"
Response.Write "非法操作!系统做了如下记录↓<br>"
Response.Write "操作IP:"&Request.ServerVariables("REMOTE_ADDR")&"<br>"
Response.Write "操作时间:"&Now&"<br>"
Response.Write "操作页面:"&Request.ServerVariables("URL")&"<br>"
Response.Write "提交方式:GET<br>"
Response.Write "提交参数:"&Fy_Get&"<br>"
Response.Write "提交数据:"&Request.QueryString(Fy_Get)
Response.End
End If
Next
Next
End If
实际上,放在全局来进行判断的方法,大多是针对整站的传参来过滤.或多或少的都会有一些问题.
个人的思路是,不去管那些在程序之间传递的参数.仅仅针对执行SQL语句时要用到的参数进行过滤.在这里,放上一个过滤函数,
public Function RSQL(strChar)
        If strChar = "" or IsNull(strChar) Then RSQL = "":Exit Function
        Dim strBadChar, arrBadChar, tempChar, I
        strBadChar="|and|exec|insert|select|delete|update|count|chr|mid|master|truncate|char|declare|1=1|char(|chr(|1=2|$|#|'|%|*|%||^|&|?|(|)|<|>|[|]|{|}|/|/|;|:|"&Chr(34) & "|" & Chr(0) & ""
        arrBadChar = Split(strBadChar, "|")
        tempChar = strChar
        For I = 0 To UBound(arrBadChar)
                tempChar = Replace(tempChar, arrBadChar(I), "")
        Next
        RSQL = tempChar
End Function

还是按照上面的例子来说明下如何使用:
postid=request("id")
postid=RSQL(postid)
set rs=server.createobject("ADODB.recordset")
sql="select * from TableName where id="&postid
rs.open sql,conn,1,1
这样,将你想过滤掉的字符都替换成空.由于仅仅针对SQL语句中要用到的参数使用.对于要写入库的数据不会有影响.就不会出现编辑器中生成的特殊字符被过滤掉的情况.需要说明的是,char(和chr(这两个被过滤的关键字.在SQL语句中可以使用char()来替换一些字符,如CHAR(104)对应的字符是h.这是将ascii编码转换成字符的函数.chr()则是在vbscript.asp中将ascii编码转换成字符的函数.希望大家再多提意见,完善过滤字符集合.

对已经完成制作的网站,大家可以按照server.objcet("ADODB.recordset")去搜索.相信绝大多数人都是把建立RS记录集和SQL语句放在一起写(当然也不排除有些人习惯不一样,呵呵),在执行每个SQL语句前,对SQL语句中的参数进行过滤.
好了,就写这么多,第一次发这样的原创贴.写起来还真是头大.语言组织能力更是有限,大家见谅.有什么不清楚的地方联系我就好了

qq:32261927

email:zhaowenmeng@foxmail.com

 

原创粉丝点击