我是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命令都在单独的类中。
答案 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。现在有很多可供选择的日子