【发布时间】:2021-12-28 23:11:09
【问题描述】:
我正在编写一个 C# 类库,其中一个特性是能够创建一个与任何现有表的架构匹配的空数据表。
例如,这个:
private DataTable RetrieveEmptyDataTable(string tableName)
{
var table = new DataTable() { TableName = tableName };
using var command = new SqlCommand($"SELECT TOP 0 * FROM {tableName}", _connection);
using SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
dataAdapter.Fill(table);
return table;
}
上面的代码可以工作,但它有一个明显的安全漏洞:SQL 注入。
我的第一直觉是像这样参数化查询:
using var command = new SqlCommand("SELECT TOP 0 * FROM @tableName", _connection);
command.Parameters.AddWithValue("@tableName", tableName);
但这会导致以下异常:
必须声明表变量“@tableName”
在 Stack Overflow 上快速搜索后,我找到了this question,它建议使用我的第一种方法(带有 sqli 漏洞的方法)。这根本没有帮助,所以我一直在搜索并找到this question,它说唯一安全的解决方案是对可能的表进行硬编码。同样,这不适用于我的类库,它需要适用于任意表名。
我的问题是:如何参数化表名而不会受到 SQL 注入的影响?
【问题讨论】:
-
SQL Server 不允许参数化的表名——你必须根据你的显示方式来做。在我上次的演出中,我们提出了许多可能的解决方案(因为我们所做的第一个查询是“哪个数据库和哪个表包含该客户的主数据”)。我们提出的一种解决方案是进行特定的表替换调用,检查表以查看它是否在数据库中的表列表中(来自
sys.tables,已缓存)。最后,我们决定接受风险并保持简单 -
@Flydog57 这也是我现在的方向。在连接到查询之前可能会进行一些清理尝试
-
如果您和我们一样,
tableName是我们从存储客户元数据的表中获取的字符串。因为它完全在我们的控制之下,并且不受用户输入或任何其他受污染的数据的影响,所以感觉没有漏洞并且不值得添加复杂性。我仍然希望在我们的数据层中使用单独的令牌格式和单独的方法来进行表名替换(它只是让我感到困扰)。我输了
标签: c# sql sql-server prepared-statement sql-injection