参数化查询为什么能够防止SQL注入
参数化查询,防止sql注入漏洞攻击 在这次重构机房收费系统中,有效的解决了SQL注入的问题,这几天对于sql注入攻击进行了详细的研究,在这里做一下回顾。
首先,什么是注入漏洞攻击呢?所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。通常的解决方案有过滤敏感字符,比如说过滤掉or, and , select sql等关键字,通过参数化查询解决sql注入漏洞的实例。
所谓的参数化查询(Parameterized Query 或 Parameterized Statement)是指在设计与数据库链接并访问数据时,在需要填入数值或数据的地方,使用参数 (Parameter) 来给值,这个方法目前已被视为最有效可预防SQL注入攻击 (SQL Injection) 的攻击手法的防御方式。Microsoft 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)的顺序来添加,否则会出错。
实例:一个简单的登录案例,登录首页
登录代码如下:
所以,入侵者只要知道了你的数据表中的任意一个用户名,就可以登录你的系统,随意更改数据表的资料,造成无法弥补的损失,但是,是不是我们没有什么改变方法呢?
下面就来讨论一下参数化查询,防止sql注入,代码如下:privatevoidbtbLogin_Click(objectsender, EventArgs e) { stringstr =@"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database2.mdf;Integrated Security=true;User Instance=true"; using(SqlConnection con=newSqlConnection (str)) { try { con.Open(); //在查询语句中使用参数 stringcmdText ="select Id from T_User where userName=@user and Password=@pwd"; using(SqlCommand cmd =newSqlCommand(cmdText, con)) {//设定参数user的值为用户输入的用户名 cmd.Parameter.Add(newSqlParameter("user",txtLoginName.Text));//设定参数pwd的值为用户输入的密码 cmd.Parameter.Add(newSqlParameter("pwd",txtPassword.Text)); inti = Convert.ToInt32(cmd.ExecuteScalar()); if(i > 0) { MessageBox.Show("Succeed to login the system !"); } else { MessageBox.Show("You have input the wrong name or password !"); } } } catch(Exception ex) { MessageBox.Show(ex.Message); } } }
在查询语句中加入@user和@pwd这样的参数,然后再为参数赋值,利用这样的形式,即可以防止该漏洞的发生。现在,登录的时候再在Password一栏里输入 1’ or ‘1’=’1 ,就不能够登录了,这样就保证了数据库的安全性。
可以看到参数化查询主要做了这些事情:
1:参数过滤,可以看到 @Password='1' or 1=1—'
2:执行计划重用
因为执行计划被重用,所以可以防止SQL注入。
小结:为参数化查询可以重用执行计划,并且如果重用执行计划的话,SQL所要表达的语义就不会变化,所以就可以防止SQL注入,如果不能重用执行计划,就有可能出现SQL注入,存储过程也是一样的道理,因为可以重用执行计划。