C# 如何修复易于SQL注入的内联C查询
下面是我编写的查询,目的是为给定where子句获取一个简单的最大值 唯一的问题是它必须经过一次代码扫描,以确定查询是否易于进行任何SQL注入 这是我的问题C# 如何修复易于SQL注入的内联C查询,c#,sql-server,C#,Sql Server,下面是我编写的查询,目的是为给定where子句获取一个简单的最大值 唯一的问题是它必须经过一次代码扫描,以确定查询是否易于进行任何SQL注入 这是我的问题 string strconnectionString = @Data Source = xxx\server; Initial Catalog =DBname; 这些是用户输入,我现在只是硬编码 private DateTime? GetFirmsLastDate() { // My user inputs hardcoded fo
string strconnectionString = @Data Source = xxx\server; Initial Catalog =DBname;
这些是用户输入,我现在只是硬编码
private DateTime? GetFirmsLastDate()
{
// My user inputs hardcoded for now
string tableName = "abc";
string columnName = "CalculationTable";
string filterColumn = "CalcValue";
string firmName = "Bank1";
using(SqlConnection connection = new SqlConnection(strconnectionString)
{
using(Sqlcommand cmd = new SqlCommand())
{
cmd.Connection = connection;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = String.Format(@"Select MAX(K.{3}) FROM {1} K WHERE K.{2} ={0}" ,
Sanitizer.GetSafeHtmlFragment(firmName),
Sanitizer.GetSafeHtmlFragment(tableName),
Sanitizer.GetSafeHtmlFragment(filterColumn),
Sanitizer.GetSafeHtmlFragment(column)
connection.Open();
object dateVal = cmd.ExecuteScalar();
return (dataVal != DBNull.Value) : DateTime.Parse(dateVal.ToString()) : null;
}
}
}
我不得不使用内联查询的原因是TableName。它是一个文本框,用户可以在其中输入表名。我无法将tableName指定为参数。为此,我必须在传递SqlCommand时准备语句
谢谢您的时间。我能想到的唯一安全方法是将内联查询更改为对存储过程的参数化调用,然后在那里优雅地处理对象名称。但是,这需要检查的列始终具有相同的数据类型。在这种情况下,我假设int: 但是,如果用户输入的值不是读取的表或列,则会生成错误。如果不希望这样,并且希望验证对象名称,则可以执行以下操作:
CREATE PROC TableMaxCount @Table sysname, @Column sysname, @Value int AS
BEGIN
DECLARE @SQL nvarchar(MAX);
SELECT @SQL = N'SELECT MAX(' + QUOTENAME(c.[name]) + NCHAR(13) + NCHAR(10) +
N'FROM ' + QUOTENAME(t.[name]) + NCHAR(13) + NCHAR(10) +
N'WHERE ' + QUOTENAME(c.[name]) + N' = @Value;'
FROM sys.tables t
JOIN sys.columns c ON t.object_id = c.object_id
JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE t.[name] = @Table
AND c.[name] = @Column
AND s.[name] = N'dbo'; --Assumes always dbo schema
EXEC sp_executesql @SQL, N'@Value int', @Value = @Value;
END
我担心我的C语言最糟糕,不过,希望您已经知道如何使用参数化代码调用SQL。如果没有,我知道文档中确实包含了它 无法参数化表名和列名。您应该向用户提供一个表名白名单,供用户选择使用某种只读UI,如列表框、组合框或下拉列表。当然,一旦选择了表的名称,同样的规则也适用于表的列名称。我不是在寻找Sql查询,我只是在寻找一个C代码。上面的查询是绝对错误的,它们是4个参数,都是字符串。我想你只是从某个地方复制粘贴了查询,但我也看到了一个很大的错误,即在sql中从未声明nvarchar max变量。请删除此答案。感谢you@user3920526因为它在那里引导你;如果您愿意,您可以轻松地将其更改为使用4个参数。你有什么理由不申报nvarcharMAX?当您需要在unicode字符串中存储超过4000个字符时,您会遇到问题。正如Steve在他的评论中提到的,您不能参数化对象,而不是您想要的方式,因此您需要使用动态SQL来实现这一点。你不喜欢这个答案并不意味着它对未来的读者没有帮助。请阅读这个问题。我在寻找一种方法,在一个内嵌的C查询中传递这个表名。您正在用sql回答我的问题。另外,您还需要使用nvarchar max从tableName中选择maxcolCount,其中filtercolumn=Colname计算有多少个字符。请删除此sql答案。如果您认为它是正确的,并不意味着它是正确的答案。我不是在看这种方法。
CREATE PROC TableMaxCount @Table sysname, @Column sysname, @Value int AS
BEGIN
DECLARE @SQL nvarchar(MAX);
SELECT @SQL = N'SELECT MAX(' + QUOTENAME(c.[name]) + NCHAR(13) + NCHAR(10) +
N'FROM ' + QUOTENAME(t.[name]) + NCHAR(13) + NCHAR(10) +
N'WHERE ' + QUOTENAME(c.[name]) + N' = @Value;'
FROM sys.tables t
JOIN sys.columns c ON t.object_id = c.object_id
JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE t.[name] = @Table
AND c.[name] = @Column
AND s.[name] = N'dbo'; --Assumes always dbo schema
EXEC sp_executesql @SQL, N'@Value int', @Value = @Value;
END