1、分析
在客户端进行身份认证登录的时候,有时候会面临字符串的脚本注入漏洞,可能会因为sql字符串的书写而添加了多个逻辑运算符进而出现账号密码的“强制匹配”。也比如说在网站中插入某个恶意的脚本窃取用户的Cookie,进而盗用客户的信息。这些问题都有可能会导致用户信息和安全的泄露。
要防止SQL注入其实不难,你知道原理就可以了。所有的SQL注入都是从用户的输入开始的。如果你对所有用户输入进行了判定和过滤,就可以防止SQL注入了。用户输入有好几种,我就说说常见的吧。
文本框、地址栏里***.asp?中?号后面的id=1之类的、单选框等等。一般SQL注入都用地址栏里的,或者在密码输入文本框中输入1’or‘1’=‘1’或者在用户名输入框中输入‘‘ or 1=1#.
2、场景模拟
我们在登录界面中的按钮中点击事件中输入:
1 private void btnLogin_Click(object sender, EventArgs e) 2 { 3 // 如何表示登陆成功了? 4 // select count(*) from tbl where uid=uid and pwd=pwd; 5 6 string uid = txtUid.Text.Trim(); 7 string pwd = txtPwd.Text; 8 9 // 验证 。。。 10 11 string connStr = ConfigurationManager.ConnectionStrings["sql"].ConnectionString; 12 13 string sql = "select count(*) from LoginTestWithPrimary where uid=‘" + uid + "‘ and pwd=‘" + pwd + "‘;"; 14 int count; 15 using (SqlConnection conn = new SqlConnection(connStr)) 16 { 17 // 执行对象 18 using (SqlCommand cmd = new SqlCommand(sql, conn)) 19 { 20 conn.Open(); 21 count = (int)cmd.ExecuteScalar(); 22 } 23 } 24 if (count > 0) 25 { 26 MessageBox.Show("登陆成功"); 27 } 28 else 29 { 30 MessageBox.Show("用户名或密码错误"); 31 32 } 33 }这样的话在密码端输入框中输入1’ or ‘1’=‘1,无论我们输入什么账户名,都会弹出登录成功MessageBox.
以此我们可以做出以下改动:
1 string pwd = txtPwd.Text.rePlace("\‘","\‘\‘");
我们也可以做出以下的调整,对Sql语句进行参数化查询,所谓的参数化就是就是将需要值的地方,用一个参数变量进行描述,也就是进行参数的替换。
1 string sql = "select count(*) from LoginTestWithPrimary where [email protected] and [email protected];";//sql查询语句 2 3 // 参数赋值 4 SqlParameter pUid = new SqlParameter("@uid123", uid); 5 SqlParameter pPwd = new SqlParameter("@pwd", pwd); 6 7 // 8 int count; 9 using (SqlConnection conn = new SqlConnection(connStr)) 10 { 11 using (SqlCommand cmd = new SqlCommand(sql, conn)) 12 { 13 // 3 将参数交给cmd 14 cmd.Parameters.Add(pUid); 15 cmd.Parameters.Add(pPwd); 16 17 18 conn.Open(); 19 count = (int)cmd.ExecuteScalar(); 20 } 21 } 22 23 if (count > 0) 24 { 25 Console.WriteLine("登陆成功"); 26 } 27 else 28 { 29 Console.WriteLine("登陆失败"); 30 }
3、结论分析
因为1=1永远是都是成立的,即where子句总是为真,将该sql进一步简化之后,等价于如下select语句: select count(*) from LoginTestWithPrimary where uid=‘123‘ and pwd=‘1‘ or ‘1‘=‘1‘。没错,该sql语句的作用是检索LoginTestWithPrimary 表中的所有字段的受影响的行数,从这条语句上看无论uid和pwd是什么,进行的或运算,结果都为真。
在使用参数化查询的情况下,数据库服务器不会将参数的内容视为sql指令的一部份来处理,而是在数据库完成sql指令的编译后,才套用参数运行,因此就算参数中含有指令,也不会被数据库运行。Access、SQL Server、MySQL、SQLite等常用数据库都支持参数化查询。这样也易形成一个规范去使用sql去操作,避免注入漏洞的问题的发生。