参数化命令执行sql语句
理解参数化指令的好处
- 防止sql注入
string sb = “SELECT *FROM admin WHERE loginid =’”+loginId+"‘AND loginPwd =’"+logingPwd+"’"
string sb =“SELECT * FROM admin WHERE loginid =” or 1=1 --AND loginPwd = ‘xxx’
使用这种拼接的方式,两种弊端:
- 不美观,而且容易出现错误。
- 安全性差,容易被sql注入攻击。
例子如下:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CH03
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("请输入用户名:");
string name = Console.ReadLine();
Console.WriteLine("请输入密码:");
string pwd = Console.ReadLine();
int count = 0;
string conStr = "data source=(local);database=MySchool;uid=sa;pwd=123456";
using (SqlConnection con = new SqlConnection(conStr))
{
con.Open();
string sql = "select count(*) from dbo.student where studentno = "+ name +" and loginpwd = '"+pwd +"'";
SqlCommand cmd = new SqlCommand(sql,con);
count = Convert.ToInt32(cmd.ExecuteScalar());
}
if (count > 0)
{
Console.WriteLine("登陆成功!");
}
else
{
Console.WriteLine("登录失败!");
}
Console.ReadKey();
}
}
}
其中我用count这个参数来接收返回的受影响的行数,若返回行数大于零,则登录成功,若返回行数小于零,则登录失败。
如果我们在用户名一栏中输入"3 or 1=1 --"则原本要去数据库查的语句
select count(*) from dbo.student where studentno = '23214' and loginpwd = '0000'
变成了
select count(*) from dbo.student where studentno = 3 or 1 = 1 -- and loginpwd = '123456'
恒成立且数据库密码给注释掉了。
执行结果count返回值固定为有值,所以也就登陆成功。
参数化查询是能有效避免上述弊端的执行sql语句的方式。
掌握使用参数化指令执行sql语句
使用@构造参数化sql命令
sqlParameter对象
- 和“@”修饰的参数一一对应,来替换该参数
通过Commend的Parameters 属性添加SqlParameter对象
SqlParameter的属性
- DbType 对应数据库的数据类型
- Direction 参数只可以输入、止可输出、双向或存储过程返回值参数
- IsNullable 参数是否接受空值
- ParameterName 参数的名称
- Size 参数对应数据的最大大小
- SqlDbType SQL Server 数据库的数据类型
- Value 参数的值
使用SqlCommmand 执行参数化SQL的步骤
- 构造数据库链接对象
- 构造参数化SQL语句
- 构造SqlParameter 对象
- 创建SqlCommand对象,使用SqlParameter对象填充数据
- 打开数据库链接,执行SqlCommand命令
例子如下:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CH03
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("请输入用户名:");
string name = Console.ReadLine();
Console.WriteLine("请输入密码:");
string pwd = Console.ReadLine();
int count = 0;
string conStr = "data source=(local);database=MySchool;uid=sa;pwd=123456";
using (SqlConnection con = new SqlConnection(conStr))
{
con.Open();
//构建参数化sql语句
string sql = "select count(*) from student where studentno =@n and loginpwd = @pwd";
//构建要替换的值,构建sqlparameter对象
SqlParameter[] par = {
new SqlParameter("@n",name),//关联
new SqlParameter("@pwd",pwd)
};
//string sql = "select count(*) from dbo.student where studentno = "+ name +" and loginpwd = '"+pwd +"'";
SqlCommand cmd = new SqlCommand(sql,con);
cmd.Parameters.AddRange(par);//添加参数化数组到cmd中
count = Convert.ToInt32(cmd.ExecuteScalar());
}
if (count > 0)
{
Console.WriteLine("登陆成功!");
}
else
{
Console.WriteLine("登录失败!");
}
Console.ReadKey();
}
}
}
再次输入sql注入方法:
传入的sql语句为:
select count(*) from student where studentno =@n and loginpwd = @pwd
而不是用+号链接的sql语句。
好处在于:
- 安全性高,有效避免SQL注入
- 代码简洁美观