SP_EXECUTESQL 中的 SQL 注入
Posted
技术标签:
【中文标题】SP_EXECUTESQL 中的 SQL 注入【英文标题】:SQL injection in SP_EXECUTESQL 【发布时间】:2019-09-07 17:09:17 【问题描述】:我在 SQL Server 中有一个存储过程,它获取一个 XML 作为输入参数。在这个 XML 中定义了 - 应该使用哪些参数值执行哪些存储过程。并根据该存储过程使用动态 SQL 和sp_executesql
执行所需的存储过程。
问题是参数的值容易受到 SQL 注入的影响。
我尝试过使用这样的类型化参数:
EXEC sys.sp_executesql
@stmt = @sql,
@params = N'@Username SYSNAME, @HireDate DATE',
@UserName = @Username, @HireDate = @HireDate;
但在我的情况下它并没有真正起作用,因为我不知道将执行带有什么参数的程序。参数的数量可能会有所不同,其中一些是可选的/具有默认值等。我能得到的只是参数的名称作为字符串:(
在对输入的 XML 进行一些解析之后,SQL 查询就这样构建和执行了
declare @params nvarchar(max);
select @params = coalesce(@params + N', ', N' ') + r.attrName + N' = ' + iif(p.isNumericType = 1, r.Value, '''' + r.Value /*cast(r.Value as nvarchar(max))*/ + '''') --+ r.Value
from dbo.#ruleConfig r
left join @spParams p on p.paramName = r.attrName -- datatype of a parameter from information_schema.parameters
declare @sql nvarchar(max) = (select @procName + isnull(@params, N''));
exec dbo.sp_executesql @sql
@sql 的值可能类似于:
'core.GetUser @LogonName = 'myDomain\myLogon''
但也可以是这样的:
'core.GetUser @fullLogonName = 'myDomain\myLogon;'WAITFOR DELAY '0:0:20';--'' and that's the problem.
【问题讨论】:
In this XML is defined - what store procedure with which parameters values should be executed.
为什么?为什么 database 解析这个字符串,而不是让客户端正确调用存储过程?那是问题的根源,而不是sp_executesql
该字符串,无论是否可以解析为 XML,本身都容易受到 SQL 注入和转换错误的影响。它也比使用 ADO.NET、ODBC 或您的语言使用的任何协议正确调用数据库大数百倍。
“但在我的情况下它并没有真正起作用,因为我不知道会执行什么程序和什么参数。” 然后你可以建立一个动态的动态语句(不理想,但我已经看到了),或者传递所有参数,无论它们是否会在动态语句中使用。 EXEC sp_executesql N'SELECT 1 AS one;',N'@i int', @i = @i;
不会出错,即使 @i
从未在“动态”查询中使用过。不过,我们这里没有任何信息,真的,无法给出完整的答案。
我认为这不可能保证安全。如果您不能信任您的用户,请不要这样做。将您的 XML 解析为单个局部变量,并在常规数据库语句中仅使用这些局部变量。
【参考方案1】:
首先,如果您有任何功能需要您发送动态 SQL 存储过程执行命令,那么您的设计就会遇到一个大问题,就像严格的紧耦合设计一样,每个 API调用将被映射到单个存储过程。
如果您仍希望坚持当前的设计,则必须创建一个已知存储过程及其值的列表。您不能仅仅接受这样一个事实,即您“不知道将执行带有什么参数的过程”,因为您按设计发布了 SQL 注入功能。
您需要创建一个已知存储过程的枚举(例如 1 = proc1、2 = proc2 等)并对它们的参数执行基于正则表达式的输入验证。
在您刚刚给出的示例中,如果您希望“myDomain\myLogon”被接受而“myDomain\myLogon;'WAITFOR DELAY '0:0:20';--”被拒绝,您可以例如使用如下所示的正则表达式:
^([A-Za-z\\])*$
您可以在regexr 网站上进行测试。 您必须为每种字段类型创建一个输入验证正则表达式 - 例如名称、用户名、电子邮件等。基本上它与为每个过程调用创建一个单独的 API 非常相似,并具有适当的输入验证。
【讨论】:
以上是关于SP_EXECUTESQL 中的 SQL 注入的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server-聚焦sp_executesql执行动态SQL查询性能真的比exec好?
Sql语句拼接(EXEC和sp_executesql的区别)