我们的高级程序员一直让我按照以下格式编写存储过程,以防止注入攻击。他说最好的做法是接受参数,然后在主体中声明一个新变量并为该 var 分配参数,这一步是针对注入攻击的额外保护,因为它强制将任何注入尝试视为数据而不是采取字面上地。真的吗?我认为这会减慢查询速度并使用额外的内存并且不会添加任何额外的保护,但我可能是错的。下面的例子。
CREATE PROCEDURE [dbo].[sp_foo_GET]
@parAcct NVARCHAR(20)
AS
BEGIN
SET NOCOUNT ON;
DECLARE
@varAcct NVARCHAR(20) = @parAcct;
SELECT [userid]
FROM [tblAccounts]
WHERE [accountID] = @varAcct;
END
编辑 在与程序员交谈后,他似乎认为将参数传递给一个变量并将它们分配给声明的变量有助于提高安全性,并且会导致查询运行得更快。
他似乎很困惑。从局部变量使用相同的值应该与从输入参数使用它没有什么不同。您的同事是否在使用参数化查询(有时称为准备好的语句)而不是完整的即席 SQL 方面走错了路?
例如:
可能是注入路径,并且在过程内部的变量之间移动值根本不会影响它,因为注入的代码不会被过程看到。如果
inputVariable
要有值xxx'; WAITFOR DELAY '00:10:00'--
,则发送到服务器的 SQL 将是您的过程将在输入参数设置为 的情况下运行,
xxx
并且根本不知道额外的代码,它在过程调用完成后运行。使用准备好的语句,假设您的数据库访问库正确支持它们并且没有在幕后做临时的愚蠢行为,这不会发生:
您的过程将使用该值调用,
xxx'; WAITFOR DELAY '00:10:00'--
而不是将额外的代码视为要执行的代码。当然,该技术可能是他希望您遵循的更大模式的一部分,当您做更高级的事情时,其目的将变得清晰,但实际上没有任何用处(除了让您养成遵循模式的习惯)阶段,但我怀疑他只是误解,因此增加了不必要的工作。能否请他详细解释一下?也许他可以为您提供一个他认为该模式可以防止的调用示例?
在评论 Re. 表现
根据你的评论,虽然我怀疑这种模式有任何安全原因,但它可能会导致性能差异的新解释更有效,尽管你可能会发现在大多数情况下它没有任何区别,在某些情况下它会降低而不是提高性能所以建议进行基准测试而不是盲目地使用该模式。
问题来自查询计划缓存以及输入参数和文字的处理方式与局部变量的处理方式不同。我不会在这里详细介绍它,因为我们偏离了原始问题(在 MS 文档和网络中搜索通常围绕短语“参数嗅探”、“查询计划缓存”和“
OPTIMIZE FOR
,然后询问新问题,如果您在阅读一些内容后需要更清楚),但作为 10 人的初学者:在上面给出的示例中,您对局部变量所做的操作实际上与使用 . 声明过程相同OPTION (OPTIMIZE FOR (@parAcct UNKNOWN))
。这个的影响与任何优化提示一样,根据过程中运行的查询和它们接触的数据的平衡,可能会有很大差异。在调试性能问题时,使用关于缓存计划的输入参数、文字和局部变量之间的差异可能很重要(这可能意味着如果您不知道,调试/测试时看到的性能配置文件与生产中看到的性能配置文件完全不同问题)。http://www.brentozar.com/archive/2014/06/tuning-stored-procedures-local-variables-problems/涵盖了这个特定上下文中的问题。