我试图制作一些用于从表中检索身份的常用代码,这涉及到使用不安全的查询字符串来注入表名。
我到处读到我无法安全地注入表名。所以我想查询表是否存在,然后根据结果执行实际或虚拟查询。
var unsafeTableQuery = "SELECT [Id] FROM [dbo].[" + tableName + "] WHERE [BulkInsertSessionID] = @bulkInsertSessionId";
var guardQuery =
"DECLARE @Exists BIT = ( SELECT CAST( COUNT(1) AS BIT ) FROM sys.tables WHERE name = @TableName AND type = 'U' );" +
"IF (@Exists = 0) SELECT TOP 0 NULL 'Id'" +
"ELSE " + unsafeTableQuery;
var cmd = new SqlCommand(guardQuery, conn, tran);
cmd.Parameters.Add(new SqlParameter("@TableName", tableName));
cmd.Parameters.Add(new SqlParameter("@bulkInsertSessionId", bulkInsertSessionId));
using (SqlDataReader reader = cmd.ExecuteReader())
{
int index = 0;
while (reader.Read())
{
int id = (int)reader[0];
entities[index++].Id = id;
}
}
即使我有一个不安全的连接,我首先要通过参数查询sys.tables
的表名。如果它不存在,IF..ELSE
块将永远不会进入不安全的查询。
为了便于阅读,我希望运行以下查询:
DECLARE @Exists BIT = ( SELECT CAST( COUNT(1) AS BIT ) FROM sys.tables WHERE name = @TableName AND type = 'U' );
IF(@Exists = 0)
SELECT TOP 0 NULL 'Id'
ELSE
SELECT [Id] from <InjectedTableName> where BulkInsertSessionID = @bulkSessionId
我认为这是安全的吗?
答案 0 :(得分:1)
假设您的用户有权更改变量tableName
。我想有些用户会在某种形式上输入它。假设他输入了这个:
Users]; DROP TABLE Users;--
然后你的整个命令将是:
DECLARE @Exists BIT = ( SELECT CAST( COUNT(1) AS BIT ) FROM sys.tables WHERE name = @TableName AND type = 'U' );
IF(@Exists = 0)
SELECT TOP 0 NULL 'Id'
ELSE
SELECT [Id] from [Users]; DROP TABLE Users;-- where BulkInsertSessionID = @bulkSessionId
这将执行其IF ELSE
部分,然后将转到下一个语句:
DROP TABLE Users;
请注意,即使ELSE
部分未执行,drop语句也会在任何情况下执行,因为您没有BEGIN END
。请注意,其余部分已注释掉......这是最基本的注射方法...