7

为了争论,假设我必须创建一个包含 SQL 查询的局部变量,该查询具有 INSERT:

 DECLARE @insert NVARCHAR(MAX)
 SELECT @insert = 'INSERT INTO [dbo].[' + @table + '] VALUES...
 EXEC (@insert) 

此 INSERT 还将包含一个列值:

 DECLARE @insert NVARCHAR(MAX)
 SELECT @insert = 
  'INSERT INTO [dbo].[' + @table + '] VALUES (N''' + @message + ''')'
 EXEC (@insert) 

现在,我显然担心注入攻击,并希望确保@message 的值不会使@insert 的值成为恶意或格式错误的对EXEC 的查询。

这给我们带来了我的问题:在@message 中转义 ' 字符是否足够?@message 中是否还有其他可能出现的字符可以逃脱?

例子:

 DECLARE @insert NVARCHAR(MAX)
 SELECT @message = REPLACE(@message,'''','''''')
 SELECT @insert = 
  'INSERT INTO [dbo].[' + @table + '] VALUES (N''' + @message + ''')'
 EXEC (@insert)  

(当我说“必须”时,这是因为我的查询在一个存储过程中,并且这个存储过程接受@table,这是要插入的目标表。我对讨论我的体系结构或为什么表不感兴趣到 INSERT into 是通过过程参数“动态”指定的。请不要对此发表评论,除非除了 EXEC() 查询之外还有另一种方法来指定要插入的表,然后将表名作为过程参数接收。)

4

5 回答 5

10

使用sp_executesql和内置的quotename(). 这篇文章,动态 SQL 的诅咒和祝福,几乎是权威的参考。

于 2009-04-01T02:40:24.347 回答
2

我建议使用sp_executesql 存储过程,而不是调用 EXEC(@somesql) 。具体来说,这允许您传递参数,系统将检查参数是否有效。

于 2009-04-01T02:42:39.363 回答
2

您可以先使用常规 T-SQL 查询架构信息,并确保首先存在表名。这样,如果它是格式错误的 SQL,它就不会作为代码执行。它只是一个 VARCHAR 表名。

DECLARE @Table AS VARCHAR(MAX)
DECLARE @Exists AS BIT

SET @Table = 'Vicious malformed dynamic SQL'

SELECT  @Exists = COUNT(TABLE_NAME) 
FROM    INFORMATION_SCHEMA.TABLES 
WHERE   TABLE_NAME = @Table

IF (@Exists = 1)
    BEGIN
    PRINT 'Table exists'
    -- Execute dynamic SQL.
    END
ELSE
    PRINT 'Invalid table'

(或者干脆使用 IF EXISTS (SELECT ....) )

于 2009-04-01T03:05:40.057 回答
0

显然,根据我的测试,即使在 2008 年,quotename() 也有 128 个长度的限制,因为它需要一个 SQL 标识符。该参考建议创建一个quotestring()函数,它与以下内容相同:

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

因此,我建议答案是从上面的 REPLACE() 中创建一个函数,如下所示:

CREATE FUNCTION quotestring(@string nvarchar(MAX)) 
RETURNS nvarchar(MAX) AS
BEGIN
    RETURN(REPLACE(@string,'''',''''''))
END

...除非我误解了什么。

于 2009-04-01T16:07:44.237 回答
0

在编写动态 SQL 时,您会希望尽可能多地进行参数化,并且仅在绝对必要时才使用字符转义。你不能参数化@table,但你可以参数化@message。

DECLARE @insert NVARCHAR(MAX)
set @insert = 'INSERT INTO [dbo].' + quotename(@table) + ' values(@message)'
exec sys.sp_executesql @insert, N'@message nvarchar(max)', @message = @inMessage;

攻击者可以通过多种方式利用动态 SQL,包括缓冲区长度攻击和使用 unicode 等效字符。我曾经遇到过一个示例,其中转义单引号字符仍然存在一个漏洞,其中可以传入引号字符的 unicode 等效项之一。软件堆栈的一部分正在进行 unicode 到 ascii 的转换,因此可以注入在他们逃脱后重新引用。哎哟。

于 2020-09-17T01:04:31.643 回答