参数化查询无效

时间:2017-03-19 12:46:32

标签: c# sql sql-injection parameterized-query

我使用DataTable填写SQL的实现如下:

var con = new SqlConnection();
var cmd = new SqlCommand();
var dt = new DataTable();
string sSQL = @"SELECT LogID, Severity, Title
                FROM dbo.Log
                WHERE UPPER(LogID) LIKE '%" + searchPhrase.ToUpper() + @"%'                        OR UPPER(Severity) LIKE '%" + searchPhrase.ToUpper() + @"%'                      OR UPPER(Title) LIKE '%" + searchPhrase.ToUpper() + @"%'                    ORDER BY " + orderBy + " " + orderFrom + @"
                OFFSET ((" + (Convert.ToInt32(current) - 1).ToString() + ") * " + rowCount + @") ROWS
                FETCH NEXT " + rowCount + " ROWS ONLY;";

try
{
    using (var connection = THF.Models.SQLConnectionManager.GetConnection())
    {
        using (var command = new SqlCommand(sSQL, connection))
        {
            connection.Open();
            command.CommandTimeout = 0;
            var da = new SqlDataAdapter(command);
            da.Fill(dt);
        }
    }
}
catch { }

这很好用,但我已经意识到由于SQL注入这很危险。所以我试图使用像这样的参数化查询来解决这个危险:

var con = new SqlConnection();
var cmd = new SqlCommand();
var dt = new DataTable();

cmd.Parameters.Add(new ObjectParameter("@searchPhrase", searchPhrase.ToUpper()));
cmd.Parameters.Add(new ObjectParameter("@orderBy", orderBy));
cmd.Parameters.Add(new ObjectParameter("@orderFrom", orderFrom));
cmd.Parameters.Add(new ObjectParameter("@current", current));
cmd.Parameters.Add(new ObjectParameter("@rowCount", rowCount));

string sSQL = @"SELECT LogID, Severity, Title
                FROM dbo.Log
                WHERE UPPER(LogID) LIKE '%" + searchPhrase.ToUpper() + @"%'                        OR UPPER(Severity) LIKE '%" + searchPhrase.ToUpper() + @"%'                      OR UPPER(Title) LIKE '%" + searchPhrase.ToUpper() + @"%'                    ORDER BY " + orderBy + " " + orderFrom + @"
                OFFSET ((" + (Convert.ToInt32(current) - 1).ToString() + ") * " + rowCount + @") ROWS
                FETCH NEXT " + rowCount + " ROWS ONLY;";

try
{
    using (var connection = THF.Models.SQLConnectionManager.GetConnection())
    {
        using (var command = new SqlCommand(sSQL, connection))
        {
            connection.Open();
            command.CommandTimeout = 0;
            var da = new SqlDataAdapter(command);
            da.Fill(dt);
        }
    }
}
catch { }

不幸的是现在我的数据表没有填写。我做错了什么?

2 个答案:

答案 0 :(得分:2)

  • 您正在使用多个命令和连接引用,不确定是否存在复制/粘贴问题或您的实际代码是这样的。在第二种情况下,它甚至不会编译。
  • 直接在查询中引用参数,请参阅下文。 Sql Server使用命名参数,因此可以在多个位置重用相同的参数。
  • Desc / Asc不能用作参数。您应该仔细检查该值或使用枚举并传递(推荐)。
  • 对rowcount的数值也是如此,将这些值作为数字传递或使用TryParse检查它们的值以确保它是数字而不是恶意代码。
  • Sql Server的默认安装选项是针对不区分大小写的联盟。这意味着您不必使用UPPER字符串进行比较。如果您确实安装了区分大小写,请不要更改此设置,否则在进行比较时会删除对UPPER的所有呼叫。
  • 最后,如果您将代码包含在try/catch中并且有一个空catch块,那么您永远不会知道为什么您的代码无效。您的代码将无声地失败,您将不知所措。不要在你的代码中的任何地方这样做,这是不好的做法!!捕获异常并处理它(执行某些操作以使代码可以恢复)或使用throw;记录并重新抛出或者根本不捕获它。我选择了后者并删除了它。

代码

var currentNum = Convert.ToInt32(current) - 1;
var temp = 0;
if(!"desc".Equals(orderFrom, StringComparison.OrdinalIgnoreCase) && !"asc".Equals(orderFrom, StringComparison.OrdinalIgnoreCase))
    throw new ArgumentException("orderFrom is not a valid value");
if(!int.TryParse(rowCount, out temp))
    throw new ArgumentException("Rowcount is not a valid number");

var dt = new DataTable();
string sSQL = @"SELECT LogID, Severity, Title
                FROM dbo.Log
                WHERE UPPER(LogID) LIKE @searchPhrase
                OR UPPER(Severity) LIKE @searchPhrase                      
                OR UPPER(Title) LIKE @searchPhrase                    
                ORDER BY @orderBy " + orderFrom + "
                OFFSET ((" + currentNum.ToString() + ") * " + rowCount + @") ROWS
                FETCH NEXT " + rowCount + " ROWS ONLY;";

using (var connection = THF.Models.SQLConnectionManager.GetConnection())
using (var command = new SqlCommand(sSQL, connection))
{
    cmd.Parameters.Add(new SqlParameter("@searchPhrase", "%" + searchPhrase.ToUpper() + "%"));
    cmd.Parameters.Add(new SqlParameter("@orderBy", orderBy));

    connection.Open();
    command.CommandTimeout = 0;
    var da = new SqlDataAdapter(command);
    da.Fill(dt);
}

答案 1 :(得分:0)

以下是一个如何完成此操作的简单示例。

con.Open();
SqlCommand cmd = new SqlCommand(@"insert into tbl_insert values(@name,@email,@add)", con);
cmd.Parameters.AddWithValue("@name", txtname.Text);
cmd.Parameters.AddWithValue("@email", txtemail.Text);
cmd.Parameters.AddWithValue("@add", txtadd.Text);
cmd.ExecuteNonQuery();
con.Close();