屌丝学编程,winform视频学习笔记

一、sql注入风险及解决方案

SQL注入是指在事先定义好的SQL语句中注入额外的SQL语句,从此来欺骗数据库服务器的行为。

示例:制作会员登录功能。

image.png 登录按钮代码如下:

private void button1_Click(object sender, EventArgs e)
        {
            //1-编写连接字符串(SQl用户名密码方式)
            string connStr = "server=.\\MSSQLSERVER1;database=DBTEST;uid=sa;pwd=********";
            //2-创建连接对象,打开连接
            SqlConnection conn = new SqlConnection(connStr);
            conn.Open();
            string sql = string.Format("select*from Member where MemberAccount='{0}' and MemberPwd='{1}'"
              , this.txtAccount.Text, this.txtPwd.Text);
            SqlDataAdapter adp = new SqlDataAdapter(sql, conn);
            DataTable dt = new DataTable();
            adp.Fill(dt);
            conn.Close();
            if (dt.Rows.Count == 0)
            {
                MessageBox.Show("用户名或密码错误!");
            }
            else
            {
                MessageBox.Show("登陆成功!");
            }
        }

==备注==:如果在用户名和密码输入框中同时输入' or '1'='1 则可以造成注入,直接登录成功,因为已经改变了原来sql语句的含义,在查询条件中有 '1'='1' 的恒等条件。 针对上述登录功能的问题风险有如下解决方案:

方案一:

对危险字符进行判断,在登录代码之前加入如下代码进行判断。

 if (this.txtAccount.Text.IndexOf("'")>=0|| this.txtPwd.Text.IndexOf("'")>=0)
            {
                MessageBox.Show("非法登录!");
                return;
            }

方案二:

优化SQL语句,先根据用户名查询,查询有记录在和密码文本框内容进行比对。

 private void button1_Click(object sender, EventArgs e)
        {
            //1-编写连接字符串(SQl用户名密码方式)
            string connStr = "server=.\\MSSQLSERVER1;database=DBTEST;uid=sa;pwd=********";
            //2-创建连接对象,打开连接
            SqlConnection conn = new SqlConnection(connStr);
            conn.Open();
            string sql = string.Format("select*from Member where MemberAccount='{0}'"
              , this.txtAccount.Text);
            SqlDataAdapter adp = new SqlDataAdapter(sql, conn);
            DataTable dt = new DataTable();
            adp.Fill(dt);
            conn.Close();
            if (dt.Rows.Count==0)
            {
                MessageBox.Show("用户名错误!");
            }
            else
            {
                if (dt.Rows[0]["MemberPwd"].ToString().Equals(this.txtPwd.Text))
                {
                    MessageBox.Show("登陆成功!");
                }
                else
                {
                    MessageBox.Show("密码错误!");
                }
            }
        }

方案三:

使用参数化方式编写sql语句

 private void button1_Click(object sender, EventArgs e)
        {
            //1-编写连接字符串(SQl用户名密码方式)
            string connStr = "server=.\\MSSQLSERVER1;database=DBTEST;uid=sa;pwd=********";
            //2-创建连接对象,打开连接
            SqlConnection conn = new SqlConnection(connStr);
            conn.Open();
            string sql = string.Format("select*from Member where MemberAccount=@MemberAccount and MemberPwd=@MemberPwd");
            SqlDataAdapter adp = new SqlDataAdapter(sql, conn);
            adp.SelectCommand.Parameters.Add(new SqlParameter("@MemberAccount", this.txtAccount.Text));//对参数进行设置
            adp.SelectCommand.Parameters.Add(new SqlParameter("@MemberPwd", this.txtPwd.Text));
            DataTable dt = new DataTable();
            adp.Fill(dt);
            conn.Close();
            if (dt.Rows.Count == 0)
            {
                MessageBox.Show("用户名或密码错误!");
            }
            else
            {
                MessageBox.Show("登陆成功!");
            }

        }

二、参数化方式实现增删改查

image.png 此示例在之前项目基础上进行修改,主要将添加数据和修改数据修改成参数化方式。

业务需求:

(1)窗体加载的时候显示数据。

(2)点击"添加数据"按钮,弹出新窗体,在新窗体中进行数据的添加,添加完成后自动刷新表格数据。

image.png (3)鼠标选中一行,右键弹出删除菜单,可以删除数据

(4)鼠标选中一行,点击"编辑数据"按钮,弹出新窗体,在新窗体中进行数据修改,修改后自动刷新表格数据。

image.png 实现步骤如下:

(1)查询窗体显示数据代码:

//绑定数据的方法
public void BindData()
{
    //1-定义连接字符串 
    //string connStr = "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=DBTEST;Data Source=.";
    //2-编写连接字符串(sql用户名密码方式连接)
    string connStr = "server=.;database=DBTEST;uid=sa;pwd=123456";
    //2-定义连接对象,打开连接
    SqlConnection conn = new SqlConnection(connStr);
    conn.Open();
    //3-编写sql语句
    string sql = "select * from Member";
    //4-数据适配器抽取信息
    SqlDataAdapter adp = new SqlDataAdapter(sql, conn);
    DataTable dt = new DataTable();  //数据表格
    adp.Fill(dt);
    this.dataGridView1.AutoGenerateColumns = false;   //自动列取消
    this.dataGridView1.DataSource = dt;
    conn.Close();
}
private void FrmSelect_Load(object sender, EventArgs e)
{
    BindData();
}

(2)删除菜单代码:

private void 删除ToolStripMenuItem_Click(object sender, EventArgs e)
        {
           
                int memid = int.Parse(this.dataGridView1.SelectedRows[0].Cells[0].Value.ToString());//选中的一行的第一单元格
                                                                                                    //数据库连接
                string connStr = "server=.\\MSSQLSERVER1;database=DBTEST;uid=sa;pwd=********";
                SqlConnection conn = new SqlConnection(connStr);
                conn.Open();
            string sql = "delete from Member where MemberId = @MemberId";
                SqlCommand cmd = new SqlCommand(sql, conn);
                cmd.Parameters.Add(new SqlParameter("MemberId", memid));
                int rowCount = cmd.ExecuteNonQuery();
                conn.Close();
                if (rowCount == 1)
                {
                    MessageBox.Show("删除数据成功!");
                }
                else
                {
                    MessageBox.Show("删除数据失败!");
                }
                BindData();
            
        }

(3)会员添加窗体代码:


 private void bt1_Click(object sender, EventArgs e)
        {
            //数据库连接
            string connStr = "server=.\\MSSQLSERVER1;database=DBTEST;uid=sa;pwd=*******";
            SqlConnection conn = new SqlConnection(connStr);
            conn.Open();
            string tempSql = "select*from Member where MemberAccount=@MemberAccount";
            SqlDataAdapter dap = new SqlDataAdapter(tempSql,conn);
            dap.SelectCommand.Parameters.Add(new SqlParameter("@MemberAccount", this.txtAcount.Text));
            DataTable dt = new DataTable();
            dap.Fill(dt);
            if (dt.Rows.Count>0)
            {
                MessageBox.Show("用户名已存在!");
                return;
            }
            //sql语句
            string sql = string.Format("insert into Member(MemberAccount,MemberPwd,MemberName,MemberPhone)values(@MemberAccount,@MemberPwd,@MemberName,@MemberPhone)");
            SqlDataAdapter adp = new SqlDataAdapter(sql, conn);
            adp.SelectCommand.Parameters.Add(new SqlParameter("@MemberAccount",this.txtAcount.Text));
            adp.SelectCommand.Parameters.Add(new SqlParameter("@MemberPwd", this.txtPwd.Text));
            adp.SelectCommand.Parameters.Add(new SqlParameter("@MemberName", this.txtName.Text));
            adp.SelectCommand.Parameters.Add(new SqlParameter("@MemberPhone", this.txtPhone.Text));
            int rowCount = adp.SelectCommand.ExecuteNonQuery();
            conn.Close();
            if (rowCount == 1)
            {
                MessageBox.Show("添加数据成功!");
            }
            else
            {
                MessageBox.Show("添加数据失败!");
            }
            ((Form5)(this.Owner)).BindData();
            this.Close();
        }

(4)会员编辑窗体代码:

private void btAdd_Click(object sender, EventArgs e)
{
    //1-编写连接字符串(windows方式连接)
    //string connStr = "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=DBTEST;Data Source=.";
    //2-编写连接字符串(sql用户名密码方式连接)
    string connStr = "server=.;database=DBTEST;uid=sa;pwd=123456";
    //2-创建连接对象,打开数据库连接
    SqlConnection conn = new SqlConnection(connStr);
    conn.Open();
    //3-编写sql语句
    string sql = string.Format("insert into Member(MemberAccount,MemberPwd,MemberName,MemberPhone)  values(@MemberAccount,@MemberPwd,@MemberName,@MemberPhone)"
            , this.txtAccount.Text, this.txtPwd.Text, this.txtNickName.Text, this.txtPhone.Text);
    //4-定义执行命令的对象执行命令
    SqlCommand cmd = new SqlCommand(sql, conn);
    cmd.Parameters.Add(new SqlParameter("@MemberAccount", this.txtAccount.Text));
    cmd.Parameters.Add(new SqlParameter("@MemberPwd", this.txtPwd.Text));
    cmd.Parameters.Add(new SqlParameter("@MemberName", this.txtNickName.Text));
    cmd.Parameters.Add(new SqlParameter("@MemberPhone", this.txtPhone.Text));
    int rowCount = cmd.ExecuteNonQuery();
    conn.Close();
    if (rowCount == 1)
        MessageBox.Show("添加成功!");
    else
        MessageBox.Show("添加失败!");
    //刷新查询窗体数据并关闭当前窗体
    ((FrmSelect)this.Owner).BindData();
    this.Close();
}

(5)查询窗体"添加数据"和"编辑数据"按钮的代码:

private void btAdd_Click(object sender, EventArgs e)
{
    FrmAdd frm = new FrmAdd();
    frm.Owner = this;
    frm.Show();
}
private void btEdit_Click(object sender, EventArgs e)
{
    if (this.dataGridView1.SelectedRows[0].Cells[0].Value.ToString().Equals(""))
    {
        MessageBox.Show("请正确选择!");
        return;
    }
    int memId = int.Parse(this.dataGridView1.SelectedRows[0].Cells[0].Value.ToString());
    FrmEdit frm = new FrmEdit();
    frm.MemId = memId;
    frm.Owner = this;
    frm.Show();
}

三、封装DBHelper类

 class DBHelper
    {
        //连接字符串
        public static string connStr = "server=.\\MSSQLSERVER1;database=DBTEST;uid=sa;pwd=********";
        //连接对象
        public static SqlConnection conn = null;
        //定义数据适配器
        public static SqlDataAdapter adp = null;
        #region 连接数据库
        public static void OpenConn()
        {
            if (conn==null)
            {
                conn = new SqlConnection(connStr);
                conn.Open();
            }
            if (conn.State==System.Data.ConnectionState.Closed)
            {
                conn.Open();
            }
            if (conn.State==System.Data.ConnectionState.Broken)
            {
                conn.Close();
                conn.Open();
            }
        }
        #endregion
        
        #region 执行sql语句前的准备(将sql传入adapter对象)
        public static void PrepareSql(string sql)
        {
            OpenConn();
            adp = new SqlDataAdapter(sql, conn);
        }
        #endregion
       
        #region 设置sql语句的参数
        public static void SetParament(string paramenterName,object paramenterValue)
        {
            paramenterName = "@" + paramenterName.Trim();
            if (paramenterValue==null)
            {
                paramenterValue = DBNull.Value;
            }
            adp.SelectCommand.Parameters.Add(new SqlParameter(paramenterName, paramenterValue));
        }
        #endregion
        
        #region 执行sql语句
        public static int ExecNonQuery()
        {
            int count = adp.SelectCommand.ExecuteNonQuery();
            conn.Close();
            return count;
        }
        public static DataTable ExecQuery()
        {
            DataTable dt = new DataTable();
            adp.Fill(dt);
            conn.Close();
            return dt;
        }
        public static SqlDataReader ExecDataReader()
        {
            return adp.SelectCommand.ExecuteReader(CommandBehavior.CloseConnection);
        }
        public static object ExecScalar()
        {
            object obj = adp.SelectCommand.ExecuteScalar();
            conn.Close();
            return obj;
        }
        #endregion
    }