使用变量表名

时间:2016-11-09 10:29:01

标签: c# sql sql-server

我试图制作一些用于从表中检索身份的常用代码,这涉及到使用不安全的查询字符串来注入表名。

我到处读到我无法安全地注入表名。所以我想查询表是否存在,然后根据结果执行实际或虚拟查询。

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

我认为这是安全的吗?

1 个答案:

答案 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。请注意,其余部分已注释掉......这是最基本的注射方法...