一、SQL注入的原因
随着B/S模式应用开发的发展,使用这种模式编写应用程序的程序员也越来越多。但是由于这个行业的入门门槛不高,程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的SQL Injection,即SQL注入。
SQL注入是从正常的WWW端口访问,而且表面看起来跟一般的Web页面访问没什么区别,所以目前市面的防火墙都不会对SQL注入发出警报,如果管理员没查看IIS日志的习惯,可能被入侵很长时间都不会发觉。
但是,SQL注入的手法相当灵活,在注入的时候会碰到很多意外的情况。能不能根据具体情况进行分析,构造巧妙的SQL语句,从而成功获取想要的数据,是高手与“菜鸟”的根本区别。
二、SQL注入的一般步骤
首先,判断环境,寻找注入点,判断数据库类型。
其次,根据注入参数类型,在脑海中重构SQL语句的原貌,按参数类型主要分为下面三种:
(A) ID=49 这类注入的参数是数字型,SQL语句原貌大致如下:
Select * from 表名 where 字段=49
注入的参数为ID=49 And [查询条件],即是生成语句:
Select * from 表名 where 字段=49 And [查询条件]
(B) Class=连续剧 这类注入的参数是字符型,SQL语句原貌大致概如下:
Select * from 表名 where 字段=’连续剧’
注入的参数为Class=连续剧’ and [查询条件] and ‘’=’ ,即是生成语句:
Select * from 表名 where 字段=’连续剧’ and [查询条件] and ‘’=’’
(C) 搜索时没过滤参数的,如keyword=关键字,SQL语句原貌大致如下:
Select * from 表名 where 字段like ’%关键字%’
注入的参数为keyword=’ and [查询条件] and ‘%25’=’, 即是生成语句:
Select * from 表名 where字段like ’%’ and [查询条件] and ‘%’=’%’
接着,将查询条件替换成SQL语句,猜解表名,例如:
ID=49 And (Select Count(*) from Admin)>=0
如果页面就与ID=49的相同,说明附加条件成立,即表Admin存在,反之,即不存在(请牢记这种方法)。如此循环,直至猜到表名为止。 表名猜出来后,将Count(*)替换成Count(字段名),用同样的原理猜解字段名。
有人会说:这里有一些偶然的成分,如果表名起得很复杂没规律的,那根本就没得玩下去了。说得很对,这世界根本就不存在100%成功的黑客技术,苍蝇不叮无缝的蛋,无论多技术多高深的黑客,都是因为别人的程序写得不严密或使用者保密意识不够,才有得下手。
三、防范方法
SQL注入漏洞可谓是“千里之堤,溃于蚁穴”,这种漏洞在网上极为普遍,通常是由于程序员对注入不了解,或者程序过滤不严格,或者某个参数忘记检查导致。在这里,我给大家一个函数,代替ASP中的Request函数,可以对一切的SQL注入说 NO。
下面我就说说用SqlParameter防SQL注入的方法
1、 SqlParameter 构造函数
SqlParameter(String, SqlDbType, Int32,ParameterDirection, Byte, Byte, String, DataRowVersion, Boolean, Object,String, String, String),其参数分别代表该类使用参数名、参数的类型、参数的长度、方向、精度、小数位数、源列名称、DataRowVersion 值之一、用于源列映射的布尔值、SqlParameter 的值、此 XML 实例的架构集合所在的数据库的名称、此 XML 实例的架构集合所在的关系架构以及此参数的架构集合的名称。
2、 SqlParameter的应用
Public Class UserDAL
''' <summary>
''' 查询用户信息
''' </summary>
''' <param name="enUserInfo"></param>
''' <returns>UserOne</returns>
''' <remarks>返回用户的基本信息实体</remarks>
Public Function Inquiry(ByVal enUserInfo As Entity.UserInfoEntity) As Entity.UserInfoEntity
'定义UserInfoEntity的一个对象
Dim UserOne As New Entity.UserInfoEntity
'获得连接字符串
Dim strConnection As String = System.Configuration.ConfigurationManager.AppSettings("sqlConnectStr")
'设置连接
Dim conn As SqlConnection = New SqlConnection(strConnection)
'定义命令对象
Dim cmd As New SqlCommand
'定义一个适配器对象
Dim sqlAdapter As SqlDataAdapter
'实例一个数据表的对象
Dim dt As New DataTable
'实例一个数据集的对象
Dim ds As New DataSet
'sal语句
Dim strSql As String = "select *from T_UserInfo where UserNO=@UserNo"
Dim paras As SqlParameter() = {New SqlParameter("@UserNo", enUserInfo.UserNo)}
'对cmd进行赋值
cmd.CommandText = strSql
cmd.CommandType = CommandType.Text
cmd.Connection = conn
cmd.Parameters.AddRange(paras)
sqlAdapter = New SqlDataAdapter(cmd)
conn.Open() '打开连接
sqlAdapter.Fill(ds) '填充数据集
dt = ds.Tables(0)
cmd.Parameters.Clear()
conn.Close()
cmd.Dispose()
Try
'对实体进行赋值
UserOne.UserNo = dt.Rows(0).Item("UserNO")
UserOne.UserName = dt.Rows(0).Item("UserName")
UserOne.UserLevel = dt.Rows(0).Item("UserLevel")
UserOne.UserPwd = dt.Rows(0).Item("UserPWD")
UserOne.RegisterManager = dt.Rows(0).Item("RegisterManager")
Return UserOne
Catch ex As Exception
Return UserOne
End Try
End Function
3、 SqlParameter的基本原理是执行计划重用。即对注入后的SQL语句重新进行了编译,重新执行了语法解析。
四、总结
不管怎么说,在今后的开发中,对于SQL注入的问题值得我们注意的还有很多,还有待于我们慢慢的积累。