使用ADO.NET的参数集合来有效防止SQL注入漏洞
string strSql = "Select * From Users Where UserName='"+name+"' and UserPwd
如果在登录时输入or 1=1这样的内容的话,name和pwd的值就会跟着改变,那我们来看
SELECT * from Users WHERE UserName = '' or '1'='1' AND UserPwd = '' or '1'='1'
还是我们刚刚的Users表,现在我要写个方法,为该表里插入记录,如下:
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
![](http://jianle.blog.51cto.com/images/editer/InBlock.gif)
简单的给个示例
传统的查询语句的sql可能为
string sql="select * from users where user_id='"+Request.QueryString["uid"]+"'";
很显然,我们在这里拼接了字符串,这就给sql注入留下了可乘之机。
现在,我们要改写这样的语句,使用SqlParameter来做
SqlCommand SqlCmd = new SqlCommand(sql, SqlConn);
SqlParameter _userid = new SqlParameter("uid", SqlDbType.Int);
_userid.Value = Request.QueryString["u_id"];
SqlCmd.Parameters.Add(_userid);
这样,我们可以保证外接参数能被正确的转换,单引号这些危险的字符也会转义了,不会再对库造成威胁。
如何再编码的过程中防范SQL注入式攻击
1、什么是SQL注入式攻击我 们知道Microsoft的SQL Server数据库是支持一次数据库查询执行多条SQL语句的,比如说再查询管理器里面,我们可以输入一条SQL语句
select * from table1 select * from table2
假如所选择的数据库中确实存在table1和table2的话,那么这个SQL语句就能够执行成功,并且能够返回正确的结果。同时,我们知道现在很多系统或者发布在Internet上的网站,管理员为了方便,一般都是直接采用sa的身份来连接数据库的,那么SQL注入式攻击主要就是抓住了系统在这么两个方面的弱点,攻击者把SQL语句插入到web表单输入,或者页面的查询字符串中,从而欺骗服务器执行恶意的SQL命令,以达到攻击的目的。
2. 注入式攻击的详细解释SQL下面我们将以一个简单的用户登陆为例,结合代码详细解释一下SQL注入式攻击,与及他的防范措施。对于一个简单的用户登陆可能的代码如下:
try
{
string strUserName = this.txtUserName.Text;
string strPwd = this.txtPwd.Text;
string strSql = "select * from userinfo where UserName="" + strUserName + "" and Password="" + strPwd + """;
SqlConnection objDbConn = new SqlConnection("数据库连接字符串");
SqlDataAdapter objAdapter = new SqlDataAdapter(strSql,objDbConn);
DataSet objDataSet = null;
objAdapter.Fill(objDataSet);//TODO 对获取的数据进行判断。
}
catch (System.Exception e)
{
this.lblMsg.Text = e.Message;
this.lblMsg.Visible = true;
}
在上面这段代码中,如果用户的输入是正常的用户名和密码的话,那么执行都会比较正常,但是,假如输入用户名的时候,输入的是“johny’--”的话,在 SQLServer里面执行的语句将会是“select * from userinfo where UserName=’johny’--‘ and Password=’密码’”,只要数据库中存在johny这个用户的话,那么不管密码是什么,语句都能够执行成功,并且能够顺利通过登陆。还 有更加厉害的,我们知道SQLServer里面有一些系统的存储过程,能够执行操作系统的很多命令,比如xp_cmdshell,假如上面用户登陆的时 候,用户名部分输入的是“johny’ exec xp_cmdshell ‘format d:/s’--”,大家想想一下后果是什么?有恶意的用户,只要把’format d:/s’这个命令稍加改造就能够做很多不合法的事情啦。
3. 如何防范SQL注入式攻击既然我们解释了为什么会产生SQL的注入式攻击,那么我们接下来说说如何来防范这种情况的发生,解决的办法有很多,我们逐个介绍一下。
a) 在进行系统部署的时候,不要采用sa来连接数据库,在数据库中新建一个帐号,对这个帐号的权限进行限制,只允许在指定的数据库里面执行一下添加,修改的权限,这样我们就可以很好地防止通过执行xp_cmdshell来攻击服务器了。
b) 采用用存储过程来执行所有的查询。SQL参数的传递方式将防止攻击者利用单引号和连字符实施攻击。此外,它还使得数据库权限可以限制到只允许特定的存储过程执行,所有的用户输入必须遵从被调用的存储过程的安全上下文,这样就很难再发生注入式攻击了。在这里大家可能会说,我只是要执行一个简单的查询,难道也要写成一个存储过程吗,这样是不是太麻烦了,其实没有关系,我们只要采用ado.net里面的SqlParameter把上面的代码稍加改造,如下
try
{
string strUserName = this.txtUserName.Text;
string strPwd = this.txtPwd.Text;
string strSql = "select * from userinfo where UserName=@UserName and Password=@Password";
SqlConnection objDbConn = new SqlConnection("数据库连接字符串");
SqlDataAdapter objAdapter = new SqlDataAdapter(strSql,objDbConn);
objAdapter.SelectCommand.Parameters.Add("@UserName",strUserName);
objAdapter.SelectCommand.Parameters.Add("@Password",strPwd);
DataSet objDataSet = null;
objAdapter.Fill(objDataSet); //TODO 对获取的数据进行判断。
}
catch (System.Exception e)
{
this.lblMsg.Text = e.Message;
this.lblMsg.Visible = true;
}
上面的这段代码,我们就可以比较好地防范SQL 注入式攻击了,原因是SQLServer里面存在一个sp_executesql的系统存储过程,ado里面只要sql语句中用到了 SqlParameter的方式的话,那么sql语句将会通过sp_executesql来执行,具体的情况大家可以用SQL Server里面的Profile来进行跟踪一下,就非常清楚了。通过这种方法,我们就即可以不用写存储过程,有能够很好地防范SQL注入式攻击了对用户的输入进行校验,将用户输入里面存在的单引号进行转义(一个单引号替换成两个单引号),并且过滤里面存在的注释符,与及特殊命令。