【问题标题】:Catching Button Tampering By a User C#捕获用户 C# 篡改的按钮
【发布时间】:2016-10-14 07:33:28
【问题描述】:

Login Error

如您所见,如果字段中没有值或与数据库中的信息不匹配,我想捕获用户篡改登录按钮的异常。

例如: 该字段没有值,我单击登录按钮一次,它说错误。单击确定按钮后,我再次单击登录按钮,现在它说, “ExecuteReader 需要一个打开且可用的连接。连接的当前状态为关闭。”

我使用 3 层架构 Windows 应用程序。

比利时:

    public SqlDataReader Login(BELLogin bellog)
    {
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = Con.getcon();
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = "SELECT username,password FROM tbl_login WHERE username = @Username AND password = @Password";
        cmd.Parameters.AddWithValue("@Username", bellog.Acctname);
        cmd.Parameters.AddWithValue("@Password", bellog.Password);
        SqlDataReader dr = cmd.ExecuteReader();
        return dr;
    }

BAL:

public class BELLogin
{
    public string Acctname { get; set; }
    public string Password { get; set; }
}

数据库连接:

public SqlConnection getcon()
    {
        if (con.State == System.Data.ConnectionState.Closed)
            con.Open();
        else if (con.State == System.Data.ConnectionState.Open)
            con.Close();
        return con;
    }

    public DataTable ExeReader(SqlCommand cmd)
    {
        getcon();
        cmd.Connection = getcon();
        SqlDataReader dr = cmd.ExecuteReader();
        DataTable dt = new DataTable();
        dt.Load(dr);
        return dt;
    }

图形界面:

private void btn_login_Click(object sender, EventArgs e)
    {
        BELog.Acctname = txb_accName.Text;
        BELog.Password = txb_password.Text;

        SqlDataReader dr;
        dr = BALog.Login(BELog);

        if (txb_accName.Text == "" || txb_password.Text == "")
        {
            MessageBox.Show("Some fields are empty. Please fill up all fields before clicking LOGIN button.", "Login Status", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        else
        {
            if (dr.HasRows == true)
            {
                dr.Read();
                Inventory Inv = new Inventory();
                Inv.Show();
                this.Hide();
            }
            else
            {
                MessageBox.Show("You have entered your password or account name incorrectly. Please check your password and account name and try again.", "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        dr.Close();
}

登录没问题,但如果用户篡改了按钮怎么办? 谢谢你帮助我:D

【问题讨论】:

  • 那似乎有 4 层?只是说
  • 第一次从ExeReader 方法调用getcon 方法是多余的,因为它在下一行再次调用,这次分配返回值。您应该删除不必要的呼叫。我进一步建议检查此代码是否存在“过度工程”...
  • 1.不要重复使用这样的连接,这是不好的做法并且没有必要。 2. 将所有实现IDisposable 的类型实例包装在using 块中,以便释放资源。在你的情况下SqlConnectionSqlCommandSqlDataReaderDataTable。见Best Practices - Executing Sql Statements
  • 从安全的角度来看,您应该从不存储您的用户密码(任何地方,不是数据库,不是文件,不是注册表等,只是不要存储它们)。您需要存储哈希值,而不是密码,然后比较哈希值。
  • 你的设计真的很糟糕。

标签: c# .net sql-server-2014


【解决方案1】:

您需要像这样在 gui 中更改代码:

//将读取器放入else子句中,并在同一个else子句中关闭读取器。理想情况下,如果遇到,您应该返回。我已经添加并评论了。

//当然,您需要付出更多努力才能使此代码更好。当你获得更多经验时,你会做到这一点。现在,这应该使您的应用程序正常工作。

private void btn_login_Click(object sender, EventArgs e)
{
     BELog.Acctname = txb_accName.Text;
     BELog.Password = txb_password.Text;

     if (txb_accName.Text == "" || txb_password.Text == "")
     {
         MessageBox.Show("Some fields are empty. Please fill up all fields before clicking LOGIN button.", "Login Status", MessageBoxButtons.OK, MessageBoxIcon.Error);
         //return;
     }
     else
     {
         SqlDataReader dr;
         dr = BALog.Login(BELog);

         if (dr.HasRows == true)
         {
             dr.Read();
             Inventory Inv = new Inventory();
             Inv.Show();
             this.Hide();
         }
         else
         {
             MessageBox.Show("You have entered your password or account name incorrectly. Please check your password and account name and try again.", "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
         }

          dr.Close();
    }
}

【讨论】:

    【解决方案2】:
    1. 不要重复使用这样的连接,这是不好的做法并且没有必要。
    2. 将所有实现IDisposable 的类型实例包装在 using 块中,以便释放资源。在你的情况下SqlConnectionSqlCommandSqlDataReaderDataTable
    3. 从安全的角度来看,您永远不应该存储您的用户密码(任何地方,不是数据库,不是文件,不是注册表等,只是不要存储它们)。您需要存储哈希值,而不是密码,并比较哈希值
    4. 坚持松耦合/高内聚原则。基本上尽可能少地从您的方法/类中公开(尤其是实现细节),以便它们可以轻松地重用和更改。目前您正在传递和共享数据库对象,这将使您的代码变得脆弱并且很难追踪问题所在。这是您的代码进行了一些重构,请注意,如果您在登录期间遇到其他连接问题,现在很容易找出问题所在。

      // 放入新的代码文件 公共类用户管理器{ public BELLogin FindLogin(字符串用户名,字符串密码){ if(string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password)) 返回空值;

          using(var connection = new SqlConnection("connectionStringPointerFromAppConfigHere"))
          using(SqlCommand cmd = new SqlCommand("SELECT username,password FROM tbl_login WHERE username = @Username AND password = @Password", connection))
          {
              connection.Open();
              cmd.Parameters.AddWithValue("@Username", bellog.Acctname).SqlDbType = SqlDbType.VarChar;
      
              // BAD practice! Use a secure hash instead and store that not the password!
              cmd.Parameters.AddWithValue("@Password", bellog.Password).SqlDbType = SqlDbType.VarChar;
              using(SqlDataReader dr = cmd.ExecuteReader())
              {
                  if(dr.Read())
                      return new BELLogin() {Acctname = dr.GetString(0), Password = dr.GetString(1)}; // passed in is same as in datareader
              }
          }
          return null;
      }
      

      }

    来自您的登录表单类

    private void btn_login_Click(object sender, EventArgs e)
    {
        if (string.IsNullOrEmpty(txb_accName.Text) || string.IsNullOrEmpty(txb_password.Text))
        {
            MessageBox.Show("Some fields are empty. Please fill up all fields before clicking LOGIN button.", "Login Status", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        else
        {
            var manager = new UserManager();
            var user = manager.FindLogin(txb_accName.Text, txb_password.Text);
    
            if (user != null)
            {
                Inventory Inv = new Inventory();
                Inv.Show();
                this.Hide();
            }
            else
            {
                MessageBox.Show("You have entered your password or account name incorrectly. Please check your password and account name and try again.", "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
    

    【讨论】:

    • 先生!你的第一个代码不是bellog。我像你说的那样创建文件,“新项目>类库> UserManager.cs”。
    • @AnjelloJoshua - 我写了place in new code file,没有放在新项目中。它可以是与现有项目位于同一项目中的文件。
    • @Igor 先生,您的代码可以工作,但是如果数据库中的用户名和密码不匹配,它就不能工作?我该怎么做?
    • @AnjelloJoshua - 定义doesn't work。当在数据库中找不到用户时,代码做了哪些不该做的事情?
    • 这是我的场景:篡改没有值的登录按钮,代码可以工作,但是将存在和不存在的值放入数据库中得到错误消息,“连接属性尚未初始化。”跨度>
    【解决方案3】:

    您的btn_login_Click 方法似乎调用BALog.Login(BELog)检查用户名和密码文本框中是否有任何有效值。只需将验证移至 btn_login_Click 方法的顶部,如果字段为空则返回:

        if (txb_accName.Text == "" || txb_password.Text == "")
        {
            MessageBox.Show("Some fields are empty. Please fill up all fields before clicking LOGIN button.", "Login Status", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }
    

    if 语句的else 部分中的代码可以保留在原处,只是不在else 中。如果用户名和密码文本框中没有有效值,该方法将因return 语句而退出。

    正如其他人所建议的,您应该检查您的代码以确保您确实需要这种结构;但如果你确实想保持这种状态,这个简单的修复将解决你的问题。

    【讨论】:

      【解决方案4】:

      只要去掉你的 DBConnection 对象,它并没有真正做任何事情,只是让你的结构变得复杂:

      public BELLogin Login(BELLogin bellog)
      {
          SqlConnection conn = new SqlConnection(connectionsString);
          try
          { 
              using (SqlCommand cmd = new SqlCommand())
              {
                 conn.Open();
                 cmd.Connection = conn;
                 cmd.CommandType = CommandType.Text;
                 cmd.CommandText = "SELECT username,password FROM tbl_login WHERE username = @Username AND password = @Password";
                 cmd.Parameters.AddWithValue("@Username", bellog.Acctname);
                 cmd.Parameters.AddWithValue("@Password", bellog.Password);
                 //really this should be in a using as well. 
                 //You be better off reading your data 
                 //into a class and returnig the class not the reader.
                 using (SqlDataReader dr = cmd.ExecuteReader())
                 {
                     BELLogin obj = new BELLogin();
                     while(dr.Read())
                     {
                          //populate obj
                     }
                     return obj;
                 }
             }
         }
         finally
         {
             conn.Close();
             conn.Dispose();
         }
      }
      

      你使用它的方式也可能导致内存泄漏,因为你没有明确地处理和关闭你的连接。始终在 C# 中处理 Sql 对象。也要警惕异常。您的代码中的任何异常都不会关闭连接等。这将导致内存泄漏和连接锁定

      【讨论】:

        猜你喜欢
        • 2021-04-16
        • 1970-01-01
        • 1970-01-01
        • 2013-05-21
        • 1970-01-01
        • 2021-11-04
        • 1970-01-01
        • 2019-04-17
        • 1970-01-01
        相关资源
        最近更新 更多