目录
一、简介
SQL注入是因为后台SQL语句拼接了用户的输入,而且Web应用程序对用户输入数据的合法性没有判断和过滤,前端传入后端的参数是攻击者可控的,攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。比如查询、删除,增加,修改数据等等,如果数据库的用户权限足够大,还可以对操作系统执行操作。
原理:WEB应用程序对用户输入的数据没有过滤或者过滤的不严谨并且把用户输入的数据当作SQL 语句带入到数据中去执行。
二、登录请求的流程
web应用程序三层架构:视图层 + 业务逻辑层 + 数据访问层:
正常的登录流程:
用户输入账户密码:张三/12345 ==>服务器执行sql语句==>select * from user where name = "张三" and password=12345;
如果这个登录存在sql注入漏洞,那么攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。
三、SQL注入容易出现的地方
登录框
搜索框
删除按钮
新增按钮
简而言之,只要与数据库发生交互,都有可能存在sql注入漏洞。
四、与 MySQL 注入的相关知识
在 MySQL5.0 版本以后,默认在数据库中存放在一个叫 infomation_schema 里面这个库里面有很多表,重点是这三个表 columns 、tables、schemata。
information_schema.schemata: 该数据表存储了mysql数据库中的所有数据库的库名。
information_schema.tables: 该数据表存储了mysql数据库中的所有数据表的表名。
information_schema.columns: 该数据表存储了mysql数据库中的所有列的列名。
4.1、MySQL开启远程登录
登录到MySQL:
mysql -uroot -p123456
use mysql;
update user set host = '%' where user = ‘root’; # %表示,所有主机都可以通过root用户访问数据库。为了方便,我直接修改成%
运行上面语句会又一个报错:
ERROR 1062 (23000): Duplicate entry ‘%-root’ for key ‘PRIMARY’
不用管,直接输入下面的命令
flush privileges; #刷新权限
由于数据库中有非常多的表我们用数据库工具navicat连接。
在连接数据库时,特别是远程连接需要用到的命令是:(此远程连接是在cmd命令中的远程连接)
mysql -h ip地址 -P 3306 -u root -p123456
-P后是端口,-u后是账号,-p后是密码 ,-h后是ip地址。
4.2、 连接数据库
连接==>选择MySQL
连接名:随便起个名字
主机:填写centos的IP(我这里是centos,填你们需要连接数据库的ip即可)
端口:默认3306
用户名:root
密码:123456 (就是设置的MySQL登录密码)
4.3、查看tables表
tables 表字段 TABLE_SCHEMA 、TABLE_NAME 分别记录着 库名 和 表名
select * from information_schema.TABLES where TABLE_SCHEMA='book'
4.4、查看columns表
选择information_schema数据库==>columns表
可以看到 columns 存储该用户创建的所有数据库的 库名、表名 和 字段名。 例如我们之前导入的book数据库。
4.5、查询book库里面所有的表和字段
通过 infomation_schema 查询 book 库里所有的表和字段
select * from information_schema.COLUMNS where TABLE_SCHEMA='book'
select TABLE_SCHEMA,TABLE_NAME from information_schema.COLUMNS where TABLE_SCHEMA='book'
#查所有的字段名
select * from information_schema.COLUMNS where TABLE_SCHEMA='book' and TABLE_NAME ='books'
#只查column_name的字段名
select COLUMN_NAME from information_schema.COLUMNS where TABLE_SCHEMA='book' and TABLE_NAME ='books'
五、SQL注入分类
5.1、按照注入点类型分类
5.1.1、数字型(整型)注入
输入的参数为整数,如ID、年龄、页码等,如果存在注入型漏洞,则为数字型(整型)注入
5.1.2、字符型注入
输入的参数为字符串
与数字型注入的区别在于:字符型注入一般要使用单引号来闭合
5.2、按照注入技术(执行效果)分类
5.2.1、联合查询注入
可以使用union的情况下的注入。
5.2.2、基于布尔的盲注
即可以根据返回页面判断条件真假的注入。
5.2.3、基于时间的盲注
即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。
5.2.4、基于报错的注入
即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
5.2.5、堆查询注入
同时执行多条语句的注入
六、 SQL注入过程
- 判断是否存在注入点;
- 判断字段长度(字段数)
- 判断字段回显位置;
- 判断数据库信息;
- 查找数据库名;
- 查找数据库表;
- 查找数据库表中所有字段以及字段值;
- 猜解账号密码;
- 登录管理员后台。
七、防御措施
严格过滤用户提交的参数
数据库信息加密
使用安全参数
使数据库服务器和web服务器分离
限制用户的权限
过滤危险函数
多层验证
八、sqli-labs 实验环境搭建
SQL注入测试工具之Sqli-labs下载安装 - 知乎 (zhihu.com)
九、sqlab教学
9.1、Less-1分析
Dhakkan 可以读成:达坎 ; parameter [pəˈræmɪtə(r)] 参数 ; numeric [nju(ː)ˈmɛrɪk] 数字 ; dump [dʌmp] 倾倒、倒出; series [ˈsɪəriːz] 系列 注:请输入 ID 作为带数字的参数。
9.1.1、传递参数
提示我们输入一个 ID 参数,我们修改 url 来传递 ID 参数 在链接后面加上 ?id=1 ,即:
http://ip地址/sqli/Less-1/?id=1
参数说明: ?表示传递参数,通常都是在页面后会有 ?id=数值,这样的方式传递参数给服务器,然后给我们返回参数对应的页面信息,我们发现我们是在/后面直接使用?传递参数,此时参数会传递给默认页面。
9.1.2、源码分析
查看第一关源码:
我们只关注最核心的代码29-30行 :
29 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
30 $result=mysql_query($sql); #mysql_query是PHP中的一个内置函数,用于执行某个针对数据库的查询
相当于在数据库中执行了以下 sql 语句:
select * from users where id =1;
9.1.3、报错信息
我们尝试在url后面添加一个单引号看一下错误信息
http://192.168.83.144/sqli/Less-1/?id=1'
报错信息为:
You have an error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1
我们分析一下报错的 SQL 语句位置 ''1'' LIMIT 0,1' 把外面一层的单引号去掉,那是用来说明报错的 SQL 语句位置的。 '1'' LIMIT 0,1
思考:这个报错可以说明什么? 就能说明此处一个 sql 注点?可以被利用?
我们看到我们输入的 id=1 此时 id 参数已经成功闭合,但是多了一个单引号导致后面的语句执行失败,由此我们可以确认当前位置存在 SQL 注入。原因是我们输入的单引号没有被过滤,成功带入数据库中执行,导致出现报错信息。所以证明这里可以注入,单引号能带入到数据库中执行,那就说明攻击者可以把恶意的SQL语句带入到数据库中。
我们加上单引号服务器执行的是:
29 $sql="SELECT * FROM users WHERE id='1'' LIMIT 0,1";
30 $result=mysql_query($sql);
9.1.4、闭合方式概述
闭合方式是指开发人员在 sql 语句中的加在参数变量两边的符号,less-1这里是单引号闭合。除了单引号 还有双引号 小括号等。
$sql="SELECT * FROM users WHERE id='1‘ --+' LIMIT 0,1";
--+表示注释,id=‘1’后面的都被--+注释掉了,其中表示注释的还有--空格、#、;%00
9.2、使用 order by 判断表中字段数
order by 关键词用于对记录集中的数据进行排序。
用法 1:按某个字段进行排序:
select * from 表名 order by 字段名;
select * from users order by username;
select * from users order by username;
用法 2:按第几个字段进行排序,如果超过查询的字段数,就报错
select * from 表名 order by 数字;
select * from users order by 2;
select * from users order by 3; #有三个字段 ,不报错
select usernmae,password from users order by 3; #会报错 说明查询的字段数量为 2 个,注意是查询的字段数量,而不是表里所有字段的数量,因为这里不是
#select *,而是 select username,password
因为我们表中只有3个字段,我们要查询10个,所以报错。
select * from users order by 10;
select * from users order by 10;
十、利用sql注入统计字段数量
10.1、载入URL
10.2、构造sql语句
execute是执行
http://192.168.83.144/sqli/Less-1/?id=1' order by 4 --+
单引号闭合 id 字段order by 4 判断是否存在 4 个字段,--+注释掉后面的 SQL 语句,大家都知道 不管什么编程语言只要注释掉就不会被执行。
十一、几种注释符号
复习:MySQL注释符号:
-- 空格
#
其他2种
提问1:这里的注释为什么不用 #
号 ?
在url中#
号是用来指导浏览器动作的(例如锚点),对服务器端完全无用。所以,HTTP请求中不包括# 将#号改成url的编码%23
就可以了。
提问2:这里的注释为什么不用 -- 空格 而用--+ ?
为了搞清楚这个问题我们修改源代码让我们更好的了解
修改Less-1代码 加上echo $sql;
把sql语句打印出来
+号在语句中变成了空格。用来和后面的单引号分隔开,将后面的语句注释。
--无法使用的原因,是因为--与后面的这个单引号连接在一起,无法形成有效的mysql语句。