SQL 注入-SQL Server 2005 联机丛书(2008 年 11 月)

在代码中检查 SQL 注入

应检查所有调用 EXECUTE、EXEC 或 sp_executesql 的代码。可以使用类似如下的查询来帮助您标识包含这些语句的过程。

SELECT object_Name(id) FROM syscomments

WHERE UPPER(text) LIKE '%EXECUTE (%'

OR UPPER(text) LIKE '%EXECUTE (%'

OR UPPER(text) LIKE '%EXECUTE (%'

OR UPPER(text) LIKE '%EXECUTE (%'

OR UPPER(text) LIKE '%EXEC (%'

OR UPPER(text) LIKE '%EXEC (%'

OR UPPER(text) LIKE '%EXEC (%'

OR UPPER(text) LIKE '%EXEC (%'

OR UPPER(text) LIKE '%SP_EXECUTESQL%'

使用 QUOTENAME() 和 REPLACE() 包装参数

在选择的每个存储过程中,验证是否对动态 Transact-SQL 中使用的所有变量都进行了正确处理。来自存储过程的输入参数的数据或从表中读取的数据应包装在 QUOTENAME() 或 REPLACE() 中。请记住,传递给 QUOTENAME() 的 @variable 值的数据类型为 sysname,且最大长度为 128 个字符。

@variable 建议的包装

安全对象的名称

QUOTENAME(@variable)

字符串 ≤ 128 个字符

QUOTENAME(@variable, '''')

字符串 > 128 个字符

REPLACE(@variable,'''', '''''')

使用此方法时,可对 SET 语句进行如下修改:

--Before:

SET @temp = N'select * from authors where au_lname='''

+ @au_lname + N''''

--After:

SET @temp = N'select * from authors where au_lname='''

+ REPLACE(@au_lname,'''','''''') + N''''

由数据截断启用的注入

如果分配给变量的任何动态 Transact-SQL 比为该变量分配的缓冲区大,那么它将被截断。如果攻击者能够通过将意外长度的字符串传递给存储过程来强制执行语句截断,则该攻击者可以操作该结果。例如,以下脚本创建的存储过程容易受到由截断启用的注入攻击。

CREATE PROCEDURE sp_MySetPassword

@loginname sysname,

@old sysname,

@new sysname

AS

-- Declare variable.

-- Note that the buffer here is only 200 characters long.

DECLARE @command varchar(200)

-- Construct the dynamic Transact-SQL.

-- In the following statement, we need a total of 154 characters

-- to set the password of 'sa'.

-- 26 for UPDATE statement, 16 for WHERE clause, 4 for 'sa', and 2 for

-- quotation marks surrounded by QUOTENAME(@loginname):

-- 200 – 26 – 16 – 4 – 2 = 154.

-- But because @new is declared as a sysname, this variable can only hold

-- 128 characters.

-- We can overcome this by passing some single quotation marks in @new.

SET @command= 'update Users set password=' + QUOTENAME(@new, '''') + ' where username=' + QUOTENAME(@loginname, '''') + ' AND password = ' + QUOTENAME(@old, '''')

-- Execute the command.

EXEC (@command)

GO

通过向 128 个字符的缓冲区传递 154 个字符,攻击者便可以在不知道旧密码的情况下为 sa 设置新密码。

EXEC sp_MySetPassword 'sa', 'dummy', '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012'''''''''''''''''''''''''''''''''''''''''''''''''''

因此,应对命令变量使用较大的缓冲区,或直接在 EXECUTE 语句内执行动态 Transact-SQL。

使用 QUOTENAME(@variable, '''') 和 REPLACE() 时的截断

如果 QUOTENAME() 和 REPLACE() 返回的字符串超过了分配的空间,该字符串将被自动截断。以下示例中创建的存储过程显示了可能出现的情况。

CREATE PROCEDURE sp_MySetPassword

@loginname sysname,

@old sysname,

@new sysname

AS

-- Declare variables.

DECLARE @login sysname

DECLARE @newpassword sysname

DECLARE @oldpassword sysname

DECLARE @command varchar(2000)

-- In the following statements, the data stored in temp variables

-- will be truncated because the buffer size of @login, @oldpassword,

-- and @newpassword is only 128 characters, but QUOTENAME() can return

-- up to 258 characters.

SET @login = QUOTENAME(@loginname, '''')

SET @oldpassword = QUOTENAME(@old, '''')

SET @newpassword = QUOTENAME(@new, '''')

-- Construct the dynamic Transact-SQL.

-- If @new contains 128 characters, then @newpassword will be '123... n

-- where n is the 127th character.

-- Because the string returned by QUOTENAME() will be truncated,

-- it can be made to look like the following statement:

-- UPDATE Users SET password ='1234. . .[127] WHERE username=' -- other stuff here

SET @command = 'UPDATE Users set password = ' + @newpassword

+ ' where username =' + @login + ' AND password = ' + @oldpassword;

-- Execute the command.

EXEC (@command)

GO

因此,以下语句将把所有用户的密码都设置为在前面的代码中传递的值。

EXEC sp_MyProc '--', 'dummy', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678'

使用 REPLACE() 时,可以通过超出分配的缓冲区空间来强迫字符串截断。以下示例中创建的存储过程显示了可能出现的情况。

CREATE PROCEDURE sp_MySetPassword

@loginname sysname,

@old sysname,

@new sysname

AS

-- Declare variables.

DECLARE @login sysname

DECLARE @newpassword sysname

DECLARE @oldpassword sysname

DECLARE @command varchar(2000)

-- In the following statements, data will be truncated because

-- the buffers allocated for @login, @oldpassword and @newpassword

-- can hold only 128 characters, but QUOTENAME() can return

-- up to 258 characters.

SET @login = REPLACE(@loginname, '''', '''''')

SET @oldpassword = REPLACE(@old, '''', '''''')

SET @newpassword = REPLACE(@new, '''', '''''')

-- Construct the dynamic Transact-SQL.

-- If @new contains 128 characters, @newpassword will be '123...n

-- where n is the 127th character.

-- Because the string returned by QUOTENAME() will be truncated, it

-- can be made to look like the following statement:

-- UPDATE Users SET password='1234…[127] WHERE username=' -- other stuff here

SET @command= 'update Users set password = ''' + @newpassword + ''' where username='''

+ @login + ''' AND password = ''' + @oldpassword + '''';

-- Execute the command.

EXEC (@command)

GO

与 QUOTENAME() 一样,可以通过声明对所有情况都足够大的临时变量来避免由 REPLACE() 引起的字符串截断。应尽可能直接在动态 Transact-SQL 内调用 QUOTENAME() 或 REPLACE()。或者,也可以按如下方式计算所需的缓冲区大小。对于 @outbuffer = QUOTENAME(@input)@outbuffer 的大小应为 2*(len(@input)+1). 。使用 REPLACE() 和双引号时(如上一示例),大小为 2*len(@input) 的缓冲区便已足够。

以下计算涵盖所有情况:

While len(@find_string) > 0, required buffer size =

round(len(@input)/len(@find_string),0) * len(@new_string)

+ (len(@input) % len(@find_string))

使用 QUOTENAME(@variable, ']') 时的截断

当 SQL Server 安全对象的名称被传递给使用 QUOTENAME(@variable, ']') 形式的语句时,可能发生截断。以下代码显示了这一可能性。

CREATE PROCEDURE sp_MyProc

@schemaname sysname,

@tablename sysname,

AS

-- Declare a variable as sysname. The variable will be 128 characters.

-- But @objectname actually must accommodate 2*258+1 characters.

DECLARE @objectname sysname

SET @objectname = QUOTENAME(@schemaname)+'.'+ QUOTENAME(@tablename)

-- Do some operations.

GO

当您串联 sysname 类型的值时,应使用足够大的临时变量来保存每个值的最多 128 个字符。应尽可能直接在动态 Transact-SQL 内调用 QUOTENAME()。或者,也可以按上一部分所述来计算所需的缓冲区大小。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12476590/viewspace-566809/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/12476590/viewspace-566809/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值