当使用 sp_executesql 作为过滤器时,保护 t-sql 动态代码的最佳方法是啥

Posted

技术标签:

【中文标题】当使用 sp_executesql 作为过滤器时,保护 t-sql 动态代码的最佳方法是啥【英文标题】:What is best way to secure t-sql dynamic code when it comes as filters using sp_executesql当使用 sp_executesql 作为过滤器时,保护 t-sql 动态代码的最佳方法是什么 【发布时间】:2020-02-11 21:01:32 【问题描述】:

我正在制作一个接受动态过滤的存储过程,我遇到的问题是我需要尽可能保持灵活性。

ALTER PROCEDURE astp_test
    @WhereClause NVARCHAR(max) = NULL
AS

DECLARE @FilteredResults AS TABLE (testId int, testfield datetime2)
DECLARE @sql AS NVARCHAR(MAX) = N'SELECT testId ,                               testfield 
                                        FROM aviw_test
                                        WHERE IsOpen = 1 AND IsLatesInsert = 1
                                            AND testStepNo = 7
                                            AND test2 IS NULL
                                            AND (testfielddate IS NULL OR testfielddate2 < GETUTCDATE()) 
                                            AND Domain IN (SELECT Domain FROM project WITH (NOLOCK) WHERE Status = ''Active'')' + 
    CASE WHEN @WhereClause IS NOT NULL 
        THEN  N' AND ' + @WhereClause ELSE N''
    END

INSERT INTO @FilteredResults
    EXEC sys.sp_executesql @stmt = @sql;

我想保护@WhereClause 输入,但以这种方式,因为有一些复选框会发送类似这样的内容:"AND testDatePick = '2019-10-10' AND testStage = 'InProgress' AND testArea = 'London' "。那么最好的方法是什么?

【问题讨论】:

最好的办法是使用动态sql。 @WhereClause 包含什么?为什么不使用 ORM 来生成好的 SQL 查询?事实上,为什么不将@sql 转换为视图并在其上编写一个简单的查询呢? PS WITH (NOLOCK) 不会让慢查询运行得更快,它会在获取额外锁的同时读取脏数据。要使这个子查询运行得更快,请在Status, Domain 上添加一个索引,并可能使用 SNAPSHOT 隔离 我不同意这一点,@PanagiotisKanavos。然而,最好的方法是 safely 注入对象名称(使用QUOTENAME)并参数化语句。但是,注入WHERE 是完全错误的想法,因为你永远无法保证它的安全。 如果您要接受原始 SQL,则没有什么好的方法可以防止任何事情发生;您必须信任客户端,因为在 T-SQL 中解析 T-SQL 是行不通的。在这种情况下,最好将查询逻辑完全集中在客户端中,这样您就可以在一个地方对其进行验证,并为不会更改的查询部分声明一个视图。我还建议阅读this article,了解有关进行动态搜索的不同、更安全的方法(以及与每种方法相关的陷阱)的大量背景信息。 我不同意笼统的说法“最好的方法是使用动态sql。” @PanagiotisKanavos。该评论已被编辑以扩大,但肯定说只是说“动态 SQL 不好”是错误的。写得不好的动态 SQL 不好,但写得好、安全的动态 SQL 很好;它的用途肯定有时间。 要“修复”(保护)它,@pixe 您需要删除该参数 @WhereClause 并将其替换为每列需要比较的 1 个参数。这需要对数据库应用程序进行更改。这是一个要求。如果不这样做,您将无法确保其安全。如果您不能这样做,我强烈建议您删除该功能。 【参考方案1】:

请试试下面的

    ALTER PROCEDURE astp_test
        @WhereClause NVARCHAR(max) = NULL
    AS

    DECLARE @FilteredResults AS TABLE (testId int, testfield datetime2)
    DECLARE @sql AS NVARCHAR(MAX) = N'SELECT testId ,                               testfield 
                                            FROM aviw_test
                                            WHERE IsOpen = 1 AND IsLatesInsert = 1
                                                AND testStepNo = 7
                                                AND test2 IS NULL
                                                AND (testfielddate IS NULL OR testfielddate2 < GETUTCDATE()) 
                                                AND Domain IN (SELECT Domain FROM project WITH (NOLOCK) WHERE Status = ''Active'')' 

if @WhereClause is not null
set @sql=@sql + 'AND ' + @WhereClause

    INSERT INTO @FilteredResults
        EXEC sys.sp_executesql @stmt = @sql;

如果您有任何问题,请告诉我

谢谢

【讨论】:

以上是关于当使用 sp_executesql 作为过滤器时,保护 t-sql 动态代码的最佳方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

是否可以使用sp_executesql将JSON作为out参数

EXEC与sp_executesql的区别及应用

SP_EXECUTESQL 中的 SQL 注入

为啥我得到“程序需要'ntext/nchar/nvarchar'类型的参数'@statement'。”当我尝试使用 sp_executesql 时?

SQLServer : EXEC和sp_executesql的区别

sp_executesql 使用