一、SQL注入的概念
SQL注入是指应用程序对用户输入的合法性没有进行校验或过滤不严导致。
二、sql注入的漏洞描述
攻击者可以在应用程序中事先定义好的查询语句后面添加sql语句,在运维管理员不知情的情况下实现非法操作,以此来欺骗数据库服务器执行非授权的任意查询的功能,进一步的获取数据库当中的敏感性信息。
三、SQL查询语句示例
SQL=" select *from '参数或字段' where id =$id "
像select * from students ,*是通配符,意思是我要查询students表中的所有信息,而where是关键词,用于查询指定的信息,如:select * from students where id = 1,意思是查询指定id为1的人的信息。
四、产生SQL注入的条件
我们传递到后端的参数是可控的。
参数内容必须代入到数据库中查询。
五、判断是否存在SQL注入
我们这里还是以上面的代码为例:SQL=" select *from '参数或字段' where id =$id "
这里的id是可控的参数,正如我们输入1的时候,数据库执行的语句应为:select *from '参数或字段' where id = 1,但当我们输入1 ' 的时候,数据库的执行语句为select *from '参数或字段' where id = 1 '。
这里第一种属于正确的书写格式,所以我们无法判断到底是否存在SQL注入,这时我们就要采用第二种办法在1后面加 ' ,由于后面有一个单引号,这样的语句不符合数据库语法的规范,所以会报错,从而判断出该处是否存在SQL注入。
六、SQL注入的分类
SQL盲注
正则注入
如:select * from users where id =1
like精准匹配注入
如:select * from students where name like "%王%"
基于时间的盲注
sleep()函数:
sleep(n)会延时显示结果,且延时的时间为 n乘查询到的记录条数。
例: select * from users where w='ww' and sleep(10) (每一条记录都会延时10秒)
注释:and前的查询语句为真的情况下,才会延时,由此可以看出到底多少条记录延时了。
基于报错的盲注
rand()随机函数,返回0~1之间的某个值
floor(a)取整函数,返回小于等于a,且值最接近a的一个整数
count()聚合函数也称作计数函数,返回查询对象的总数
group by clause分组语句,按照查询结果分组
通过报错来显示出具体的信息。
查询的时候如果使用rand()的话,该值会被计算多次。在使用group by的时候,floor(rand(0)*2)会被执行一次,如果虚表不存在记录,插入虚表的时候会再被执行一次。
如:select count() from information_schema.tables group by concat(version(), floor(rand(0)*2))
等等。
因为实在是太详细了,我以后会单独出一片SQL注入语句的文章。
七、SQL注入的防御
采用预编译技术
预编译阶段可以优化 sql 的执行
预编译之后的 sql 多数情况下可以直接执行,DBMS 不需要再次编译,越复杂的sql,编译的复杂度将越大,预编译阶段可以合并多次操作为一个操作。可以提升性能。
防止SQL注入
使用预编译,而其后注入的参数将不会再进行SQL编译。也就是说其后注入进来的参数系统将不会认为它会是一条SQL语句,而默认其是一个参数,参数中的or或者and 等就不是SQL语法保留字了。
严格控制数据类型
在JAVA、C等强类型语言中一般是不存在数字型注入的,因为在接受到用户输入id时,代码一般会做一个int id 的数据类型转换,假如我们输入的是字符串的话,那么这种情况下,程序就会报错。但是在PHP、ASP这些没有强调处理数据类型的语言,一般我们看到的接收id的代码都是。
如:id = $_GET['id'];
SQL = "select * from '某字段' where id = $id;";
这样的代码攻击者就可以通过构造id参数运用联合查询等手法进行SQL注入,假如这里我们加入一个检查数字类型函数is_numeric()这样就可以防止数字型注入了。
对特殊参数和字符进行转义
数字型注入可以通过检查数据类型防止,但是字符型不可以,那么怎么办呢,最好的办法就是对特殊的字符进行转义了。比如在MySQL中我们可以对" ' "进行转义,这样就防止了一些恶意攻击者来闭合语句。当然我们也可以通过一些安全函数来转义特殊字符。如addslashes()等,但是这些函数并非一劳永逸,攻击者还可以通过一些特殊的方式绕过。