参数化查询与SQL注入

时间:2013-07-07 04:06:21

标签: c# asp.net

我是Asp.net的新手,我刚刚开始上课。我最近创建了一个类来处理我的大部分SQL查询,这样我就不必在所有文件上重复创建新的连接。

我创建的其中一个方法将SQL查询作为参数,并返回结果。我知道我应该使用参数化查询来避免SQL注入。我的问题是,当我将查询作为字符串参数传递时,我该怎么做?

例如,这是我将要调用的方法:

public static DataTable SqlDataTable(string sql)
{
    using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
    {
        SqlCommand cmd = new SqlCommand(sql, conn);
        cmd.Connection.Open();
        DataTable TempTable = new DataTable();
        TempTable.Load(cmd.ExecuteReader());
        return TempTable;
    }
}

所以从另一个文件中我想像这样使用这个方法:

DataTable dt = new DataTable();

dt = SqlComm.SqlDataTable("SELECT * FROM Users WHERE UserName='" + login.Text  + "' and Password='" + password.Text + "'");

if (dt.Rows.Count > 0)
{
   // do something if the query returns rows
}

这有效,但仍然容易受到注射吗?有没有办法可以将变量作为参数传递给字符串?我知道如果我为查询创建一个新的SQLCommand对象并使用Parameters.AddWithValue,我可以这样做,但我希望所有的SQL命令都在单独的类中。

4 个答案:

答案 0 :(得分:14)

  

这样可行,但仍然容易受到注射吗?

是的,您的代码非常容易受到SQL注入攻击。

  

我知道我应该使用参数化查询来避免SQL注入。

哦,绝对是的。

  

我的问题是,当我将查询作为字符串参数传递时,我该怎么做?

您根本不应该将查询作为字符串参数传递。相反,您应该将查询作为包含占位符的字符串参数和这些占位符的值传递:

public static DataTable SqlDataTable(string sql, IDictionary<string, object> values)
{
    using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
    using (SqlCommand cmd = conn.CreateCommand())
    {
        conn.Open();
        cmd.CommandText = sql;
        foreach (KeyValuePair<string, object> item in values)
        {
            cmd.Parameters.AddWithValue("@" + item.Key, item.Value);
        }

        DataTable table = new DataTable();
        using (var reader = cmd.ExecuteReader())
        {
            table.Load(reader);
            return table;
        }
    }
}

然后使用你的函数:

DataTable dt = SqlComm.SqlDataTable(
    "SELECT * FROM Users WHERE UserName = @UserName AND Password = @Password",
    new Dictionary<string, object>
    {
        { "UserName", login.Text },
        { "Password", password.Text },
    }
);

if (dt.Rows.Count > 0)
{
   // do something if the query returns rows
}

答案 1 :(得分:0)

您正在尝试做的事情具有完美的逻辑意义,我可以理解为什么要实现这一目标。但是,您尝试做的事情是非常危险的,作为ASP.NET的新手,您可能不会意识到有多种其他选项可供您使用,这使您可以更轻松,更安全地管理数据。 / p>

@iamkrillin暗示了一种这样的技术 - 对象关系映射(ORM)。 .NET框架实际上具有对名为Entity Framework的ORM的一流支持。我相信他建议你研究ORM的原因是因为你的设计实际上与ORM的工作方式非常相似。它们是抽象类,表示数据库中可以使用LINQ轻松查询的表。 LINQ查询自动参数化,减轻了管理查询安全性的压力。它们动态生成SQL(与将字符串传递给数据访问类时的方式相同),并且在返回数据的方式上更加灵活(数组,列表,您可以命名)。

然而,ORM的一个缺点是它们具有非常陡峭的学习曲线。一个更简单的选择(虽然比EF稍早)将使用Typed Datasets。类型化数据集比站立ORM更容易创建,并且通常更容易实现。虽然没有ORM那么灵活,但它们以一种简单,安全且已经解决的方式完成了您正在尝试做的事情。幸运的是,当ASP.NET首次出现时,培训视频主要集中在类型化数据集上,因此有各种高质量的freely available videos/tutorials可以帮助您快速启动和运行。

答案 2 :(得分:0)

你走在正确的轨道上,我实际上也完成了你自己想要做的事情。但是,我不是只是将一个字符串传递给你的函数,而是传入一个SQL Command对象...所以这样,你可以正确地构建所有的命令和参数,然后说...在这里,去运行它,它准备出发了。像

这样的东西
public static DataTable SqlDataTable(SqlCommand cmd)
{
    using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
    {  
        cmd.Connection = conn;   // store your connection to the command object..
        cmd.Connection.Open();
        DataTable TempTable = new DataTable();
        TempTable.Load(cmd.ExecuteReader());
        return TempTable;
    }
}

public DataTable GetMyCustomers(string likeName)
{
    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = "select * from SomeTable where LastName like "@someParm%";
    cmd.Parameters.Add( "whateverParm", likeName );  // don't have SQL with me now, guessing syntax

    // so now your SQL Command is all built with parameters and ready to go.
    return SqlDataTable( cmd );
}

答案 3 :(得分:-3)

我的建议:使用一个orm。现在有很多可供选择的日子