SQL Server:清理@param以防止注入攻击
为了便于讨论,我们假设我必须创建一个包含具有 INSERT 的 SQL 查询的局部变量:
DECLARE @insert NVARCHAR(MAX)
SELECT @insert = 'INSERT INTO [dbo].[' + @table + '] VALUES...
EXEC (@insert)
此 INSERT 还将包含一个列值:
DECLARE @insert NVARCHAR(MAX)
SELECT @insert =
'INSERT INTO [dbo].[' + @table + '] VALUES (N''' + @message + ''')'
EXEC (@insert)
现在,我显然很担心关于注入攻击,并希望确保 @message 的值不会使 @insert 的值成为恶意或格式错误的 EXEC 查询。
这给我们带来了我的问题:转义 @message 中的 ' 字符就足够了吗? @message 中是否还有其他可能出现的字符可以逃逸?
示例:(
DECLARE @insert NVARCHAR(MAX)
SELECT @message = REPLACE(@message,'''','''''')
SELECT @insert =
'INSERT INTO [dbo].[' + @table + '] VALUES (N''' + @message + ''')'
EXEC (@insert)
当我说“必须”时,这是因为我的查询位于存储过程中,并且该存储过程接受 @table,这是要 INSERT 到的目标表。我不是有兴趣讨论我的体系结构或为什么要插入的表是通过过程参数“动态”指定的,请不要对此发表评论,除非除了 EXEC() 查询之外还有其他方法来指定要插入的表。然后表名作为过程参数被接收。)
For the sake of argument, let's just say I have to create a local variable containing a SQL query that has an INSERT:
DECLARE @insert NVARCHAR(MAX)
SELECT @insert = 'INSERT INTO [dbo].[' + @table + '] VALUES...
EXEC (@insert)
This INSERT is also going to contain a column value:
DECLARE @insert NVARCHAR(MAX)
SELECT @insert =
'INSERT INTO [dbo].[' + @table + '] VALUES (N''' + @message + ''')'
EXEC (@insert)
Now, I'm obviously concerned about an injection attack, and would like to ensure that @message's value can't make @insert's value malicious or malformed as a query to EXEC.
This brings us to my question: is escaping the ' characters in @message sufficient? Are there any other characters that could appear in @message that could escape out?
Example:
DECLARE @insert NVARCHAR(MAX)
SELECT @message = REPLACE(@message,'''','''''')
SELECT @insert =
'INSERT INTO [dbo].[' + @table + '] VALUES (N''' + @message + ''')'
EXEC (@insert)
(When I say "have to", this is because my query is in a stored procedure, and this stored procedure accepts @table, which is the destination table to INSERT into. I'm not interested in discussing my architecture or why the table to INSERT into is "dynamically" specified via a procedure parameter. Please refrain from commenting on this unless there's another way besides EXEC()ing a query to specify a table to INSERT into when then table name is received as a procedure parameter.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
使用
sp_executesql
和内置quotename()
。 这篇文章动态 SQL 的诅咒与祝福几乎是权威的参考资料。Use
sp_executesql
and the built-inquotename()
. This article, The Curse and Blessings of Dynamic SQL, is pretty much the definitive reference.您可以先使用常规 T-SQL 查询架构信息,并确保表名首先存在。 这样,如果它是格式错误的 SQL,它就不会作为代码执行。 它只是一个 VARCHAR 表名。
(或者简单地使用 IF EXISTS (SELECT ....) )
You could first query the schema information with regular T-SQL and make sure the table name exists first. This way, if it's malformed SQL, it won't execute as code. It will just be a VARCHAR table name.
(Or simply use IF EXISTS (SELECT ....) )
我建议使用 sp_executesql 存储过程。 具体来说,这允许您传递参数,系统将检查参数是否有效。
Rather than calling EXEC(@somesql), I suggest using the sp_executesql stored procedure. Specifically, this allows you to pass parameters, and the system will check that the parameters are valid.
显然,根据我的测试,即使在 2008 年,quotename() 也有 128 长度的限制,因为它需要一个 SQL 标识符。 该参考建议创建一个 quotestring() 函数,它的作用与:
因此,我建议答案是从上面的 REPLACE() 创建一个函数,如下所示:
...除非我误解了某些内容。
Apparently there's a 128-length limit to quotename(), even in 2008 according to my test, since it expects a SQL identifier. The reference suggests creating a quotestring() function, which does the same thing as:
Therefore I am proposing that the answer is to create a function out of the REPLACE() above, like so:
...Unless I've misunderstood something.
在编写动态 SQL 时,您将希望尽可能多地参数化,并且仅在绝对必要时才采用字符转义。 您不能参数化@table,但可以参数化@message。
攻击者可以通过多种方式利用动态 SQL,包括缓冲区长度攻击和使用 unicode 等效字符。 我曾经遇到过一个例子,转义单引号字符仍然存在一个漏洞,可以传入引号字符的 unicode 等效项之一。软件堆栈的一部分正在执行 unicode 到 ascii 的转换,因此可以注入他们逃脱后引用回来。 哎哟。
When writing dynamic SQL you'll want to parameterise as much as possible, and only resort to character escaping when you absolutely have to. You can't parameterise @table, but you can parameterise @message.
There are a lot of ways attackers can exploit dynamic SQL, including buffer length attacks and using unicode equivalent characters. I encountered an example once where escaping the single quote char still had a vulnerability where one of the unicode equivalents of the quote char could be passed in. Part of the software stack was doing a unicode to ascii conversion, so it was possible to inject a quote back in after they were escaped. Ouch.