如何保护带有参数化表名的查询不被注入
Posted
技术标签:
【中文标题】如何保护带有参数化表名的查询不被注入【英文标题】:How to protect queries with parameterised table names from injection 【发布时间】:2019-10-09 16:31:45 【问题描述】:在寻找一种与同一服务器上不同表中的数据交互的方法时,我遇到了this question 上提供的解决方案。据我所知,没有其他方法可以将表名“传递”给查询。问题是它似乎容易受到 SQL 注入的影响;例如,我可以使用此代码将某人添加到名为“School1”的数据库中的“学生”表中:
CREATE PROCEDURE AddStudent (
@DBName char(10),
@FirstName char(30),
@LastName char(30)
) AS
DECLARE @SqlScript varchar(MAX) = '
INSERT INTO ' + @DBName + '.dbo.student (FirstName, LastName) VALUES (' +
@FirstName + ', ' + @LastName + ');'
EXECUTE (@SqlScript)
当我调用存储过程“AddStudent”时,我只需传递变量“School1”、“Bobby”和“Tables”。您可能会看到这是怎么回事...
即使数据库名称以某种方式以编程方式(因此安全地)确定客户端,little Bobby Tables could choose to use his full name 并用 @FirstName
破坏一切 = Robert,@LastName
= '); DROP TABLE student;--给我们带来了各种各样的问题。
当然,这可能是一个不太可能和极端的例子,但你明白了。有什么办法可以预防吗?
【问题讨论】:
是的 - 不要使用动态 SQL - 我知道你不想为每个需要更新的表编写 SP 的痛苦,但这是正确/正确/安全的方法。跨度> @DaleBurrell 所以你会建议客户端IF DbName = School1 THEN <run SP for School1 DB> ...
类型的东西吗?或者我可以将条件语句放入过程中以使用预定义的数据库运行第二个?
好吧,我不了解您的客户端,但通常人们使用某种形式的域建模,其中每个类(通常与数据库记录密切相关)是由不同的代码处理。现在很多人都在使用 ORM。即使是手工编码,我有代码要维护,每个类的代码都是独立的,并保存到自己的数据库表中。
我开始倾向于我评论中的第二个想法 - 构建一个测试环境以尝试将 DBName 和数据变量传递给一个 SP,该 SP 根据一组选项检查 DBName,然后通过剩余变量到适当的第二个 SP...
【参考方案1】:
Dale 提到我必须为每个数据库有一个单独的存储过程,这让我想到了将它分成两个单独的存储过程;一个只计算出要使用的数据库,然后将值传递给另一个,它实际上添加了学生记录。它不是特别优雅,但它可以让你在 SQL 中做很多事情:
首先,添加学生的查询,正如您所期望的那样 - 将其放入每个数据库中:
CREATE Procedure [dbo].[AddStudent] (@FirstName char(10), @LastName char(10)) AS
INSERT INTO SCHOOL1.dbo.Student (FirstName, LastName) VALUES
(@FirstName, @LastName);
然后是另一个,它可以存在于主数据库中,也可以存在于每个数据库中,具体取决于最方便将其发送到的位置:
CREATE Procedure [dbo].[AddStudentUniversal] (@DbName char(10), @FirstName char(10), @LastName char(10)) AS
IF (@DbName = 'SCHOOL1') EXECUTE SCHOOL1.dbo.AddStudent @FirstName, @LastName
IF (@DbName = 'SCHOOL2') EXECUTE SCHOOL2.dbo.AddStudent @FirstName, @LastName
【讨论】:
以上是关于如何保护带有参数化表名的查询不被注入的主要内容,如果未能解决你的问题,请参考以下文章