【问题标题】:Correct usage of Dynamic SQL in SQL ServerSQL Server 中动态 SQL 的正确使用
【发布时间】:2018-02-26 01:22:42
【问题描述】:

我 99% 的时间都在使用静态 SQL,但最近的一个场景让我编写了一个动态 SQL,我想确保在这个 SQL 发布到生产环境之前我没有遗漏任何东西。

表名是前缀、2字母变量和后缀的组合,列名是前缀+2字母变量。

首先,我检查了 @p_param 的长度为 2 个字母并且被“列入白名单”:

IF (LEN(@p_param) = 2 and (@p_param = ‘aa’ or @p_param = ‘bb’ or @p_param = ‘cc’ or @p_param = ‘dd’ or @p_param = ‘aa’)

    BEGIN
        set @p_table_name = 'table_' + @p_param + '_suffix';
        set @sql = 'update ' + QUOTENAME(@p_table_name) + ' set column_name = 2 where id in (1,2,3,4);';
        EXEC sp_executesql @sql;

--Here I’m checking the second parameter that I will create the column name with
        IF (LEN(@p_column) = 2 and (@p_column = 'ce' or @p_column = 'pt')
           BEGIN
               Set @column_name = 'column_name_' + @p_column_param; 
               set @second_sql = 'update ' + QUOTENAME(@p_table_name) + ' set ' + 
                                  QUOTENAME(@column_name) + ' = 2 where id in (@p_some_param);';

               EXEC sp_executesql @second_sql, N'@p_some_param NVARCHAR(200)', @p_some_param = @p_some_param;
           END

    END

这个用例安全吗?有什么我应该注意的陷阱吗?

【问题讨论】:

  • 我认为您确信 column_name 存在于 @p_table_name 中?同样,您确信@column_name 的数据类型能够插入一个整数,并且您不需要检查它的数据类型?我还要添加一个 'else' 语句:“插入 failed_queries(table, column) 值 (@p_param, @p_column);”
  • 是的,所有这些条件都应该满足,如果不满足,那么我可以假设客户发送了不应该发送的东西。
  • 我认为检查长度并确保参数在白名单中是多余的,但比抱歉更安全。我认为您的问题可能与该解决方案的长期可支持性有关,而不是您的具体实施;最好(我认为)有一个表,其中 p_param 和 p_column 是字段中的值。换句话说,我认为这会奏效,但我认为应该对其进行重新设计,以便以更标准的方式完成——这应该使其性能更高,并且在一两年内让其他人更容易支持?
  • 我认为您可以安全地进行 SQL 注入。但是,在其他方面使用该数据库似乎很烦人,表名和列名基本上没有意义。需要注意的是,如果 @p_some_param 是一个列表,那么该查询将不会按您期望的方式工作。
  • 请注意,列名和表确实有意义,为了这个问题,我已经更改了它们。我知道@p_some_param 不能按原样工作,我正在使用一个函数来处理这个问题。

标签: sql-server tsql dynamic-sql


【解决方案1】:

似乎您在翻译无意义的名称时丢失了一些东西,以便准备您的查询以在此处发布,所以这有点难以判断。不过,我觉得整体方法还可以。

为标识符使用带有QUOTENAME 的白名单将保护您免受使用标识符参数的SQL 注入,并将值参数作为参数传递给sp_executeSql 将保护您免受使用值参数的SQL 注入,所以我会说你在这方面做得很好。

不过,有几件事我会改变。
除了针对硬编码的白名单测试您的表和列名称之外,我还将针对information_schema.columns 进行测试,以确保在缺少表或列的情况下该过程不会引发错误。
此外,您的白名单条件可以得到改善 - 而不是:

IF (LEN(@p_param) = 2 and (@p_param = ‘aa’ or @p_param = ‘bb’ or @p_param = ‘cc’ or @p_param = ‘dd’ or @p_param = ‘aa’)

你可以简单地写:

IF @p_param IN('aa', 'bb', 'cc','dd')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-26
    • 2023-04-09
    • 2014-11-24
    • 2016-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-05
    相关资源
    最近更新 更多