参数化查询,防止sql注入漏洞攻击
2011-03-25 11:14 focusdada 阅读(450) 评论(0) 收藏 举报首先,什么是注入漏洞攻击呢?所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。通常的解决方案有过滤敏感字符,比如说过滤掉or,
and , select sql等关键字,但是,这种方法存在一定的缺陷,在这里不做讨论,我们只看参数化查询解决sql注入漏洞的实例。
所谓的参数化查询(Parameterized Query 或 Parameterized
Statement)是指在设计与数据库链接并访问数据时,在需要填入数值或数据的地方,使用参数 (Parameter)
来给值,这个方法目前已被视为最有效可预防SQL注入攻击 (SQL Injection) 的攻击手法的防御方式。Microsoft SQL Server
的参数格式是以 "@" 字符加上参数名称而成,SQL Server 亦支持匿名参数 "?"。
例如:SELECT * FROM myTable WHERE myID = @myID
INSERT INTO myTable (c1, c2, c3, c4) VALUES (@c1, @c2, @c3, @c4)或者SELECT * FROM
myTable WHERE myID = @myID INSERT INTO myTable (c1, c2, c3, c4)
VALUES(?,?,?,?),通过(?)指定占位符,当然在添加参数的时候,必须按照(c1, c2, c3, c4)的顺序来添加,否则会出错。
实例:一个简单的登录案例,登录首页

登录代码如下:
01 privatevoidbtbLogin_Click(objectsender, EventArgs e)
02 {
03 String str = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database2.mdf;Integrated Security=true;User Instance=true";
04 using(SqlConnection con=newSqlConnection (str))
05 {
06 try
07 {
08 con.Open();
09 stringcmdText = "select Id from T_User where userName='"+txtLoginName.Text +"' and Password='"+txtPwd.Text+"'";
10 using(SqlCommand cmd = newSqlCommand(cmdText, con))
11 {
12 //返回第一行id的值,如果id>0,则证明登录成功
13 inti = Convert.ToInt32(cmd.ExecuteScalar());
14 if(i > 0)
15 {
16 MessageBox.Show("Succeed to login the system !");
17 }
18 else
19 {
20 MessageBox.Show("You have input the wrong name or password !");
21 }
22 }
23 }
24 catch(Exception ex)
25 {
26 MessageBox.Show(ex.Message);
27 }
28 }
29
30 }
分析:
数据表T_User中含有一条数据,userName为admin,Password为123,这样的话输入正确的话能登陆到系统。当用户名输入admin后,在password一栏里输入 1’ or ‘1’=’1 之后按登录按钮,惊奇的发现也能登录成功。
原因输出现在这里: tring cmdText = "select Id from T_User where userName='"+txtLoginName.Text() +"' and Password='"+txtPwd.Text()+"'"; 这是一句查询语句,采用的是连接字符串的形式。当在sqlserver中输入select * from T_User where userName='admin' and Password ='1' or '1'='1' 这条语句时, sqlserver是正确执行的,也就是返回T_User表中的所有数据。这也就是为什么会发生sql注入漏洞的原因。
数据表T_User中含有一条数据,userName为admin,Password为123,这样的话输入正确的话能登陆到系统。当用户名输入admin后,在password一栏里输入 1’ or ‘1’=’1 之后按登录按钮,惊奇的发现也能登录成功。
原因输出现在这里: tring cmdText = "select Id from T_User where userName='"+txtLoginName.Text() +"' and Password='"+txtPwd.Text()+"'"; 这是一句查询语句,采用的是连接字符串的形式。当在sqlserver中输入select * from T_User where userName='admin' and Password ='1' or '1'='1' 这条语句时, sqlserver是正确执行的,也就是返回T_User表中的所有数据。这也就是为什么会发生sql注入漏洞的原因。

所以,入侵者只要知道了你的数据表中的任意一个用户名,就可以登录你的系统,随意更改数据表的资料,造成无法弥补的损失,但是,是不是我们没有什么改变方法呢?
当然不是了,下面就来讨论一下参数化查询,防止sql注入,代码如下:
01 privatevoidbtbLogin_Click(objectsender, EventArgs e)
02 {
03 stringstr = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database2.mdf;Integrated Security=true;User Instance=true";
04 using(SqlConnection con=newSqlConnection (str))
05 {
06 try
07 {
08 con.Open();
09 //在查询语句中使用参数
10 stringcmdText = "select Id from T_User where userName=@user and Password=@pwd";
11 using(SqlCommand cmd = newSqlCommand(cmdText, con))
12 {
1 //设定参数user的值为用户输入的用户名
1 cmd.Parameter.Add(newSqlParameter("user",txtLoginName.Text));
1 //设定参数pwd的值为用户输入的密码
01 cmd.Parameter.Add(newSqlParameter("pwd",txtPassword.Text));
02
03 inti = Convert.ToInt32(cmd.ExecuteScalar());
04 if(i > 0)
05 {
06 MessageBox.Show("Succeed to login the system !");
07 }
08 else
09 {
10 MessageBox.Show("You have input the wrong name or password !");
11 }
12 }
13 }
14 catch(Exception ex)
15 {
16 MessageBox.Show(ex.Message);
17 }
18 }
19
20 }
在查询语句中加入@user和@pwd这样的参数,然后再为参数赋值,利用这样的形式,即可以防止该漏洞的发生。现在,登录的时候再在password一栏里输入
1’ or ‘1’=’1 ,就不能够登录了,这样就保证了数据库的安全性。
小结:参数化查询能够安全高效的对sql进行条件查询,所以在以后的开发工作过程中,尽量使用参数化的sql语句,防止注入漏洞的发生。
浙公网安备 33010602011771号