为什么我们应该使用QUOTENAME功能?

时间:2016-10-07 13:56:24

标签: sql-server tsql

我熟悉QUOTENAME功能。但我不明白我能用什么呢?为何如此广泛使用?

select quotename('[abc]') -- '[[abc]]]'
select quotename('abc') -- '[abc]'
select '[' + 'abc' +']'  -- why it is not so good as previous?

2 个答案:

答案 0 :(得分:6)

想象一下,计划定期运行以下脚本来清理dbo模式以外的模式中的表。

DECLARE @TABLE_SCHEMA SYSNAME,
        @TABLE_NAME   SYSNAME
DECLARE @C1 AS CURSOR;

SET @C1 = CURSOR FAST_FORWARD
FOR SELECT TABLE_SCHEMA,
           TABLE_NAME
    FROM   INFORMATION_SCHEMA.TABLES
    WHERE  TABLE_SCHEMA <> 'dbo'

OPEN @C1;

FETCH NEXT FROM @C1 INTO @TABLE_SCHEMA, @TABLE_NAME;

WHILE @@FETCH_STATUS = 0
  BEGIN
      PRINT 'DROP TABLE [' + @TABLE_SCHEMA + '].[' + @TABLE_NAME + ']';

      EXEC ('DROP TABLE [' + @TABLE_SCHEMA + '].[' + @TABLE_NAME + ']');

      FETCH NEXT FROM @C1 INTO @TABLE_SCHEMA, @TABLE_NAME;
  END 

如果您创建以下内容并运行脚本,则尽管使用手动字符串连接方法,但所有内容都按预期工作。表foo.bar已被删除。

CREATE SCHEMA foo
CREATE TABLE foo.bar(x int)

现在创建以下内容并尝试

CREATE TABLE foo.[[abc]]](x int)

脚本失败并显示错误

DROP TABLE [foo].[[abc]]
Msg 105, Level 15, State 1, Line 6
Unclosed quotation mark after the character string '[abc]'.
Msg 102, Level 15, State 1, Line 6
Incorrect syntax near '[abc]'.

因此,不使用QUOTENAME导致脚本失败。关闭括号没有通过加倍来正确逃脱。正确的语法应该是

DROP TABLE [foo].[[abc]]]

更糟糕的是,恶意开发者已经了解了脚本的存在。它们在脚本计划运行之前执行以下命令。

CREATE TABLE [User supplied name]]; 
EXEC sp_addsrvrolemember 'SomeDomain\user2216', 'sysadmin';  --]
(
x int
)

现在最终执行的脚本是

DROP TABLE [foo].[User supplied name]; 
EXEC sp_addsrvrolemember 'SomeDomain\user2216', 'sysadmin';  --]

]被解释为关闭对象名称,余数被解释为新语句。第一个语句返回一条错误消息,但没有一个范围终止一个,第二个语句仍然执行。通过不使用QUOTENAME,您已经开启了SQL注入,并且开发人员已成功升级其权限

答案 1 :(得分:1)

生成动态SQL语句时可以使用

QUOTENAME。它确实会将您的列名放在括号之间,但也会转义会破坏您引用的列名并可能导致SQL注入的字符。

例如:

SELECT QUOTENAME('abc[]def'); 

将返回:

[abc[]]def]  

了解更多信息:QUOTENAME (MSDN)