7

我是 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

4 回答 4

15

这有效,但仍然容易受到注射,对吗?

是的,您的代码非常容易受到 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
}
于 2013-07-07T12:41:20.607 回答
0

您正在尝试做的事情具有完美的逻辑意义,我可以理解您为什么会实现此实施。但是,您尝试做的事情是非常危险的,并且作为 ASP.NET 的新手,您可能不知道还有许多其他选项可供您使用,这些选项可以使您的数据管理更加轻松和安全。

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

然而,ORM 的一个缺点是它们的学习曲线非常陡峭。一个更简单的选项(虽然比 EF 稍早)是使用类型化数据集。类型化数据集比建立 ORM 更容易创建,并且通常更容易实现。虽然不如 ORM 灵活,但它们以简单、安全且已经解决的方式完成了您想要做的事情。幸运的是,当 ASP.NET 第一次出现时,培训视频主要集中在类型化数据集上,因此有各种高质量的免费视频/教程可以帮助您快速上手。

于 2013-07-07T05:01:57.503 回答
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 );
}
于 2013-07-07T12:18:46.767 回答
-3

我的建议:使用 orm。从现在开始有很多选择

于 2013-07-07T04:08:40.950 回答