SQL注入以及解决的办法

我们以前很可能听过一个词语叫做SQL注入攻击,其是威胁我们系统安全的最危险的因素之一,那么到底什么是SQL注入攻击呢?这里我会用一个最经典最简单的例子来跟大家解释一下:
众所周知,我们的sql语句都是有逻辑的,例如下面这句:

select * from usertable where username='admin' and password='abc123'

这句超级简单吧,我们都知道,这句最常用的是在登陆的时候,来查询用户输入的账号和密码匹配不匹配,来确定用户是否可以登陆的,大体上一看好像没啥问题,但是呢,假如我是一名黑客,我可以用一种巧妙地方式来登陆你这个系统,我账号随意输入一个,密码我输入一个 1 ‘or’ 1’='1 什么意思呢?请看下面这个语句:

select * from usertable  where username='asasas' and password='1 'or '1'='1'

这一句是啥意思呢?
我的账号输入的是asasas,乱输的,但我的密码输入的是1 ‘or’ 1’=‘1 ,最后在数据库里查询的上面这句,其实是一句恒等式,为什么这么说呢?where条件后面有一个and 还有一个or,我们都知道and是且,or是或,所以整个语句的条件其实是名字为asasas且密码为1或者’1’等于’1’,这里就很好笑了,字符串1永远等于字符串1啊!所以后面的where条件是一个恒等式,表所有的行都符合字符串1等于字符串1这个条件,又是或的关系,所以所有的行全部匹配,全部被搜索出来,这样再用行数来判断用户是否能登陆已经根本不行了,因为查出来的是所有行。就类似于下面的句子:

从信息表查询,姓名是(a),密码是(111)的所有行。
从信息表查询,姓名是(a),密码是(111或者1=1)的所有行。
从信息表查询,姓名是(a),密码是(111)或者(1=1)的所有行。

注意第二句,改写成第三句后大家应该能看懂了,第三句肯定会查询出来所有的行。
既然现在大家基本了解了SQL注入攻击,那我们要怎么办才能防止这种攻击发生呢?
第一种方式大家都很容易想到,那就是特殊字符匹配,首先大多数系统不会允许用户输入特殊字符 ',- - 之类的,这可以解决一部分SQL注入问题,但是目前最有效最简单的方法是参数化查询语句来防止SQL注入,大家可能看得一脸懵逼,什么是参数化查询语句?没关系,请看下面的代码:

        //usernameValue:前台用户传过来的用户名的值 
        //passwordValue:前台用户传过来的密码的值 
        using (SqlConnection cn = new SqlConnection())
        {
            cn.ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["TESTDB"].ConnectionString;
            cn.Open();

            using (SqlCommand cmd = new SqlCommand())
            {
                string sqlSentence  = "select COUNT(*) from usertable where UserName = @UserName and Password = @Password ";
                //声明两个SqlParameter来做参数化替换
                SqlParameter username = new SqlParameter("@UserName", usernameValue);
                SqlParameter password = new SqlParameter("@Password", passwordValue);
                cmd.Connection = cn;
                cmd.CommandText = sqlSentence;
                //参数化替换
                cmd.Parameters.Add(username);
                cmd.Parameters.Add(password);
                //语句执行
                cmd.ExecuteNonQuery();
            }
        }
        
        

这就是一段经典的参数化sql语句执行,可能大家觉得这种方式和我们去拼接字符串执行看起来没什么差别,实际上,这两种方式差别非常大,其中最重要的差别就在于这种方式会将执行计划重用,大家可能又要问什么是执行计划重用,执行计划重用是数据库的一种机制,其预编译sql语句,就类似于一个模板,以后执行的话就改改传入参数,就不需要再次编译了,举个简单的例子,刚才我们的:

//执行计划
从信息表查询,姓名是( ),密码是( )的所有行。
从信息表查询,姓名是(a),密码是(111)的所有行。
从信息表查询,姓名是(a),密码是(111或者1=1)的所有行。
从信息表查询,姓名是(a),密码是(111)或者(1=1)的所有行。

第一句就相当于一个执行计划,它是编译产生的一个模板,确定以后数据库没有特殊情况就再也不会去编译这一句,语意就确定了,只是参数一直在变,这样能加快数据库执行的速度,重用执行计划就是重复使用这一个语意来执行数据库语句,再来看我们的第四句,第四句明显语意发生了变化,需要数据库重新进行编译,但实际上,其语意变化并不是我们想看到的,所以我们只需要将其强制性的按照原先的语意进行执行,便是我们所想看到的结果,所以,参数化sql的作用就在这里,具体sql参数化后执行的具体语句四什么样子的,大家可以自行百度,但是一定是用到了sp_executesql这个关键字,这个关键字就是用来做强制重用执行计划的,所以,大家以后在后台写sql语句拼接时,尽量多使用sql参数化的方式,可以大大提高安全性。
That’s All.

原创文章 24 获赞 2 访问量 875

猜你喜欢

转载自blog.csdn.net/weixin_43653187/article/details/106120036