在 SQL 服务器中正确使用 Dynamic SQL

Correct usage of Dynamic SQL in SQL Server

我 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

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

似乎您在翻译为无意义名称的过程中丢失了一些东西以准备您在此处向 post 查询,因此很难判断。但是,整体方法对我来说似乎还可以。

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

不过,我会更改一些内容。
除了针对硬编码白名单测试您的 table 和列名称外,我还会针对 information_schema.columns 进行测试,只是为了确保程序不会在 [= 情况下引发错误28=] 或缺少列。
此外,您的白名单条件可以改进 - 而不是:

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')