4

我正在从事 C# 项目,我是这项技术的新手。

我想从 SQL Server 2008 中读取一些数据,我编写了以下代码

public User select(string username, string password)
{
    string connection = ConfigurationManager.ConnectionStrings["lawyersDBConnectionString"].ConnectionString.ToString();
    string sql = string.Format("select * from users where userName = '{0}' and password = '{1}'", username, password);

    SqlConnection con = new SqlConnection();            
    con.ConnectionString = connection;

    DataSet ds = new DataSet();
    SqlDataAdapter da = new SqlDataAdapter(sql, con);            

    User user = new User();
    DataRow dr;

    try
    {
            da.Fill(ds);
            dr = ds.Tables[0].Rows[0];

            user.Id = Convert.ToInt16(dr["userID"]);                
            user.FirstName = (string)dr["firstName"];
            user.LastName = (string)dr["lastName"];
            user.Email = (string)dr["email"];
            user.Username = (string)dr["userName"];
            user.Password = (string)dr["password"];
            user.type = (string)dr["type"];

            return user;
    }
    catch (Exception ex)
    {                
            return null;
    }
}//end of select method

但是我看过一篇关于SQL注入的文章,我想用SQL参数来避免这种情况,但我不知道怎么做。

4

3 回答 3

9

这是对您的代码的简单返工。未经测试,但本质上它包括在一次性对象周围添加using 语句以及使用 SqlCommand 及其参数集合

string connection = ConfigurationManager.ConnectionStrings ["lawyersDBConnectionString"].ConnectionString.ToString();
string sql = "select * from users where userName = @uname and password = @pwd";

 DataSet ds = new DataSet();
 using(SqlConnection con = new SqlConnection(connection))
 using(SqlCommand cmd = new SqlCommand(sql, con))
 {
    con.Open();
    cmd.Parameters.AddWithValue("@uname", username);
    cmd.Parameters.AddWithValue("@pwd", password);

    using(SqlDataAdapter da = new SqlDataAdapter(cmd))
    {
         User user = new User();
         DataRow dr;
         da.Fill(ds);
         dr = ds.Tables[0].Rows[0];

         user.Id = Convert.ToInt16(dr["userID"]);                
         user.FirstName = (string)dr["firstName"];
         user.LastName = (string)dr["lastName"];
         user.Email = (string)dr["email"];
         user.Username = (string)dr["userName"];
         user.Password = (string)dr["password"];
         user.type = (string)dr["type"];
         return user;
    }
}

注意命令文本如何不直接包含用户和密码的字符串,而是一个简单的参数占位符(@uname and @pwd)。在将参数添加到 SqlCommand 集合时,这些占位符被称为参数名称。

查看检索到的数据的使用情况,我强烈建议您查看简单的 ORM 工具,例如Dapper,它可以直接翻译 User 对象中的所有这些代码

于 2013-09-11T22:28:22.853 回答
1

有趣的是,String.Format 的工作方式与 SQL 参数没有太大区别。唯一真正的区别是您指定每个参数的数据类型,它允许 SQLCommand 正确清理(阅读:防止 sql 注入)您的用户输入。

下面是一个示例,说明如何更改代码以使用 SQL 参数。

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    using (SqlCommand command = new SqlCommand("select * from users where userName = @pUsername and password = @pPassword", connection))
    {
        command.Parameters.Add(new SqlParameter("pUsername", username));
        command.Parameters.Add(new SqlParameter("pPassword", password));

        DataSet ds = new DataSet();
        SqlDataAdapter da = new SqlDataAdapter(command);  

        // The rest of your code here...
     }
}

不过我想指出几点:

  1. 用户名通常不区分大小写,因此查询可能应该使用 LIKE 或 UCASE() 比较来查找用户名。
  2. 从查询中可以明显看出您的密码没有经过哈希处理或加盐处理。这真是太糟了。阅读散列密码。https://crackstation.net/hashing-security.htm
  3. 基本上,您在这里创建的东西称为对象关系管理器。除非您对学习如何开发一个特别感兴趣,否则我强烈建议您使用经过尝试和测试的一个。我个人使用 nHibernate。Hibernate 是作为 Java 的 ORM 编写的,nHibernate 在 .Net 应用程序中非常流行。Entity Framework 是微软的 ORM。我不认为它与 nHibernate 相当,但它在不断改进。
于 2013-09-11T22:35:32.917 回答
0

这是我为该需求编写的可重用方法:

public static DataSet GetDataSetWithParameters(string query, List<SqlParameter> parameters)
{
    DataSet ds = new DataSet();
    SqlConnection Con = new SqlConnection(ConnectionString);
    Con.Open();

    try
    {
        using (SqlCommand cmd = new SqlCommand(query, Con))
        {
            if (parameters != null)
            {
                cmd.Parameters.AddRange(parameters.ToArray());
            }

            using (SqlDataAdapter Adapter = new SqlDataAdapter(cmd))
            {
                Adapter.Fill(ds);
            }

            return ds;
        }
    }
    catch
    {
        throw;
    }
    finally
    {
        CloseConnection(ref Con);
    }
}
于 2019-07-27T14:09:49.297 回答