存储过程中是否存在此 SQL 注入漏洞?

Is this SQL Injection Vulnerability in Stored Procedure?

提问人:Ob Ahmed 提问时间:6/7/2023 最后编辑:Ob Ahmed 更新时间:6/7/2023 访问量:133

问:

我正在使用一个名为 GetPublicMethodData 的存储过程,该过程根据用户输入执行动态 SQL 查询。我的经理指出了代码中潜在的 SQL 注入漏洞,我正在寻求有关如何有效解决此问题的指导。

下面是用于调用存储过程的代码Exec GetPublicMethodData 'GetFilterData', N'{"Make_Id": 1}'

下面是存储过程的代码:Here's the code for the stored procedure:

Create PROCEDURE GetPublicMethodData
    @MethodKeyword NVARCHAR(MAX),
    @ParamKeyword_JSON NVARCHAR(MAX)
AS
BEGIN
    DECLARE @Result NVARCHAR(MAX);
    DECLARE @Query NVARCHAR(MAX);
    DECLARE @MethodName NVARCHAR(MAX);
    DECLARE @MethodId BIGINT = 0;

    SELECT @MethodId = MethodId, @MethodName = MethodName FROM SYS_PublicMethod WHERE MethodKeyword = @MethodKeyword;
    
    SELECT @Result = COALESCE(@Result + ', ', '') + P.Parameter + ' = ' +
        CASE
            WHEN ISJSON([value]) = 1 THEN [value]
            ELSE '''' + [value] + ''''
        END
    FROM OPENJSON(@ParamKeyword_JSON) J
    INNER JOIN SYS_PublicParam P ON P.ParamKeyword COLLATE SQL_Latin1_General_CP1_CI_AS = J.[key] COLLATE SQL_Latin1_General_CP1_CI_AS
    WHERE MethodId = @MethodId

    SET @Query = 'EXEC ' + QUOTENAME(@MethodName) + ' ' + ISNULL(@Result, '');

    EXEC sp_executesql @Query;
END;

根据我的理解,代码似乎很好,因为@Query值将类似于 EXEC [GetFilterData] @Make_Id = '1'

P.S. 我已经在 csharp JSONString.Replace(“'”,“''”) 中用 1 个单引号替换了 2 个单引号

有关解决此存储过程中的 SQL 注入漏洞的指导和建议将非常有价值。感谢您在解决此安全问题方面的专业知识和帮助。

更新: 要求是构建一个架构,在该架构中,我们不需要为存储过程创建 API。因此,只有 1 个 API 会以安全的方式调用所有存储过程。

以下是从 POSTman 到注入的参数

{
    "JSONSTRING": "{\"MakeId\":\"2' Delete From TestPayment\"}"
}

@Query值将是

EXEC [GetFilterData] @Make_Id = '2'' 删除自 TestPayment'

sql sql-server sql 注入

评论

0赞 Thom A 6/7/2023
这闻起来像 XY 问题。你为什么首先要做上述事情?为什么一个过程要调用另一个过程?为什么不让用户调用?你为什么要注入而不是参数化它的价值?GetFilterData@Result
0赞 Thom A 6/7/2023
更不用说语法是有据可查的反模式,应该避免;它依赖于数据引擎逐行处理 U,这是无法保证的。相反,使用字符串聚合来实现相同的结果。但是,在最新版本的 SQL Server 中,需要使用 (和 ) 才能获得相同的结果。SELECT @Variable = @Variable + ... FROMSTRING_AGGFOR XML PATHSTUFF
0赞 Ob Ahmed 6/7/2023
@ThomA 实际上,要求是构建一个不需要为存储过程创建 API 的架构。因此,只有 1 个 API 会以安全的方式调用所有存储过程。
2赞 Thom A 6/7/2023
绝对闻起来像 XY 问题
3赞 Damien_The_Unbeliever 6/7/2023
这几乎感觉就像内部平台效应,你正在采用一个现有的系统,它允许你将存储过程的名称和一些参数传递给它,并在其中构建一些可以......获取要运行的过程的名称和一些参数,然后执行该过程。你不太可能构建比你已经在里面构建的系统更强大的东西。

答:

0赞 user21994727 6/7/2023 #1

更多的评论,注入可能是可能的(Make_Id中没有要替换的单个引号,但那里有引号)

Exec GetPublicMethodData 'GetFilterData', N'{"Make_Id":"1\u0027;SELECT 1234[inject];PRINT\u0027"}'

评论

0赞 Charlieface 6/7/2023
取决于是打开还是关闭。但总的来说,你的观点是站得住脚的:还有其他攻击角度QUOTED_IDENTIFIER
0赞 Ob Ahmed 6/8/2023
@user21994727 谢谢,还有其他方法吗?