中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档 | 网通镜像
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 数据库开发 > MSSQL Server
带SQL server注入漏洞的分页存储过程
作者:knowsky.com 时间:2007-06-25 16:24 出处:knowsky.com 责编:月夜寒箫
              摘要:带SQL server注入漏洞的分页存储过程

在Google中搜索“分页存储过程”会出来好多结果,是大家常用的分页存储过程,今天我却要说它是有漏洞的,而且漏洞无法通过修改存储过程进行补救。

通常大家都会认为存储过程可以避免SQL Server注入的漏洞,这适用于一般的存储过程,而对于通用分页存储过程是不适合的,请看下面的代码和分析!

 

一般的通用的分页存储过程代码如下:

 

CREATE PROCEDURE pagination
            @tblName varchar(255), -- 表名
            @strGetFields varchar(1000) = '*', -- 需要返回的列
            @fldName varchar(255)=', -- 排序的字段名
            @PageSize int = 10, -- 页尺寸
            @PageIndex int = 1, -- 页码
            @doCount bit = 0, -- 返回记录总数, 非 0 值则返回
            @OrderType bit = 0, -- 设置排序类型, 非 0 值则降序
            @strWhere varchar(1500) = ' -- 查询条件 (注意: 不要加 where)
            AS
            declare @strSQL varchar(5000) -- 主语句
            declare @strTmp varchar(110) -- 临时变量
            declare @strOrder varchar(400) -- 排序类型
            if @doCount != 0
            begin
            if @strWhere !='
            set @strSQL = 'select count(*) as Total
            from [' + @tblName + '] where '+@strWhere
            else
            set @strSQL = 'select count(*) as
            Total from [' + @tblName + ']'
            end

 

--以上代码的意思是如果@doCount传递过来的不是0,就执行总数统计。以下的所有代码都是@doCount为0的情况。

 

 

else
            begin
            if @OrderType != 0
            begin
            set @strTmp = '<(select min'
            set @strOrder = ' order by [' + @fldName +'] desc'
            --如果@OrderType不是0,就执行降序,这句很重要!
            end
            else
            begin
            set @strTmp = '>(select max'
            set @strOrder = ' order by [' + @fldName +'] asc'
            end
            if @PageIndex = 1
            begin
            if @strWhere != '
            set @strSQL = 'select top ' + str(@PageSize) +'
            '+@strGetFields+ ' from [' + @tblName + '] where
            ' + @strWhere + ' ' + @strOrder
            else
            set @strSQL = 'select top ' + str(@PageSize) +'
            '+@strGetFields+ ' from ['+ @tblName + '] '+ @strOrder
            --如果是第一页就执行以上代码,这样会加快执行速度
            end
            else
            begin
            --以下代码赋予了@strSQL以真正执行的SQL代码
            set @strSQL = 'select top ' + str(@PageSize) +'
            '+@strGetFields+ ' from ['
            + @tblName + '] where [' + @fldName + ']' + @strTmp + '
            (['+ @fldName + ']) from (select top ' + str((@PageIndex-1)*@PageSize) + '
            ['+ @fldName + '] from [' + @tblName + ']' + @strOrder + ') as tblTmp)'
            + @strOrder
            if @strWhere != '
            set @strSQL = 'select top ' + str(@PageSize) +' '+@strGetFields+ ' from ['
            + @tblName + '] where [' + @fldName + ']' + @strTmp + '(['
            + @fldName + ']) from (select top ' + str((@PageIndex-1)*@PageSize) + ' ['
            + @fldName + '] from [' + @tblName + '] where ' + @strWhere + ' '
            + @strOrder + ') as tblTmp) and ' + @strWhere + ' ' + @strOrder
            end
            end
            exec (@strSQL)
            GO

 

 

大家可以看到上面的存储过程中是通过一些步骤最终拼接成一个SQL Server字符串,然后通过exec执行这个串得到分页的结果。

 

 

我们假定要做一个这样的查询,通过用户名UserName模糊查询用户,为了叙述方便,便于理解我们只考虑取第一页的情况,取出存储过程中取第一页的拼串行如下:

 

set @strSQL = 'SELECT TOP ' + str(@PageSize) + '
            ' + @strGetFields + ' from [' + @tblName + ']  where ' + @strWhere + '
            ' + @strOrder

为了便于说明问题,我们可以假定@pageSize为20,@strGetFields为 ‘*’,@tblName为UserAccount,@strOrder为’ ORDER BY ID DESC’ 那么上面一行可以写成如下形式:

 

set @strSQL = 'SELECT TOP 20 *  from [UserAccount]
            where ' + @strWhere  + '
            ORDER BY ID DESC’

我们可以假定用户输入的模糊用户名是: Jim’s dog。

 

我们用SQL Parameter传递参数给分页存储过程@strWhere 的值是:’UserName LIKE ‘’%Jim’’ dog%’’’(注意LIKE后边的字符串中的单引号已经全部变成两个单引号了),我们将这个值代入上面的@strSQL赋值语句中,如下:

 

 

set @strSQL = 'SELECT TOP 20 *  from [UserAccount]
            where  UserName LIKE '%Jim' dog%' ORDER BY ID DESC’
            让我们写上声明变量的部分执行在查询分析器中测试一下,代码如下:
            DECLARE @strSQL varchar(8000)
            DECLARE @strWhere varchar(1000)
            SET @strWhere = 'UserName LIKE '%Jim' dog%''
            set @strSQL = 'SELECT TOP 20 *  from [UserAccount]  where
            ' + @strWhere + ' ORDER BY ID DESC'
            print @strSQL
            exec (@strSQL)

大家可以把上面几行代码粘贴到查询分析器中执行一下,就可以看到下面的画面:

 

 

在消息的第一行,打印出了要执行的SQL Server语句,很显然此语句的 LIKE ‘%Jim’ 后面的部分全部被截断了,也就是说如果用户输入的不是Jim’s dog而是Jim’ delete from UserAccount那么会正确的执行删除操作,传说中的SQL Server注入就会出现了。

 

 

问题出现了,我们应该怎么解决问题?

 

1.很显然我们使用SqlParameter传递参数已经将单引号替换成了连个单引号了,可是因为我们在数据库中拼串导致替换并不能解决问题。

 

2.根据我的实验证明如果使用存储过程不可能解决这个问题,我们只有将这个存储过程要执行的拼串操作放到数据访问层去做,才可以避免这个问题。

 

备注:本文说的是MS SQL Server2000 的数据库,而非使用SQL Server2005的新特性分页。

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有