Hello,各位小伙伴大家好~
这里是你们的小编Monster .
今天起开始更新JAVA代码审计相关内容了~
首先从大家最熟悉的SQL注入讲起
包含以下内容:
(1)JDBC下的JAVA代码审计
(2)Mybatis下的JAVA代码审计
(3)Hibernate下的JAVA代码审计
因为是从零开始的代码审计分享
所以本套分享会从环境搭建开始讲起~
今天的内容是JDBC下的JAVA代码审计,
一起来看看吧,Here We Go!
Part.1
JDBC初探
什么是JDBC?
想要学习SQL注入,就需要从最简单的JDBC看起,什么是JDBC呢?
JDBC是JAVA访问各种不同数据库的统一标准规范,该规范用于定义接口,具体的实现由各大数据库厂商各自实现。
因此我们只需要会调用JDBC接口中的方法即可,不用关注背后的类是怎么实现的,由数据库厂商提供数据库驱动,从用户侧大大简化了数据库的配置难度。
JDBC的核心API如下所示:
主要通过两种方法执行SQL语句,分别是:
Statement
PrepareStatement
因此我们审计JDBC下的SQL注入,就可以从以上两个函数入手。
JDBC环境搭建
既然是手把手教学,那么我们就从零开始写一套JDBC代码熟悉一下。
//本文使用的所有源码都可以从文末获取!!
我们来写一个用户登录的简单场景。
首先通过DBeaver、Navicat等工具连接本地数据库,并创建多个账号用于登录:
接着我们来看看如何创建一个java web项目。
打开idea,新建一个项目:
//这里通过tomcat8.5版本启动,jdk使用1.8版本:
选择web服务,点击Finash完成创建:
创建完成后,查看Project Settings可以看到项目的资源配置情况:
//例如源码为src/main/java文件夹
接下来开始配置jdbc,创建一个lib文件用于放mysql数据库驱动:
右键Add as library,进行调用:
创建类user,变量与数据库中user表对应:
//get、set方法用于调用、修改变量值
创建类demo01,配置数据库连接:
//除此之外还有c3p0,druid等多种配置方式,功能都是一样的,代码审计无需过多关注。
右键运行demo01,因为我密码错误,这里出现报错:
修改password为正确口令后,顺利连接上数据库:
添加用于输入用户名、口令的代码:
接下来,配置statement用于执行sql语句:
//结合if语句,查询并判断用户名、口令是否正确
查询完毕后还需要释放掉statement连接:
尝试查询一下,输入正确用户名、口令:
输入错误的用户名、口令:
环境搭建完毕~
Part.2
JDBC注入审计
Statement拼接不当
上面的环境就是采用的Statement方式进行SQL查询:
可控点为name和password字段:
代码语言:javascript复制select * from user where name='name' and passwd=’password’;
如果输入:
代码语言:javascript复制name=admin‘ #
password=123123
则可通过sql注入绕过登录密码:
因为此时的查询语句变成了:
代码语言:javascript复制select * from user where name='name' #' and passwd=’123123’
第一个单引号让#号键发生了逃逸,并注释了后面的密码查询字段,实际执行的语句是:
代码语言:javascript复制select * from user where name='name‘
可以看出Statement方法是不安全的。
PrepareStatement拼接不当
PrepareStatement 是 Statement 接口的子接口,继承父接口中的所有方法,并且它是一个预编译的 SQL 语句。
相较于Statement,PrepareStatement有两个优势:
(1)因为有预先编译的功能,提高 SQL 的执行效率。
(2)预编译可以有效的防止 SQL 注入的问题,安全性更高。
理论上PrepareStatement安全性更好,但如果误用也会导致SQL注入存在。
修改上述代码为:
这里采用prepareStatement方式执行sql语句,但依然存在注入:
原因在于PrepareStatement方法需要使用“?”对变量位进行占位才会进行预编译。
修改代码为:
此时再尝试sql注入,已经失败了:
order by等特殊情况
那是不是我们使用预编译的方式,就可以避免sql注入了?
答案是否定的,因为有些情况是不适用预编译的。
预编译在对?传参过程中,会给所传的参数前后加上单引号。
首先将数据库中id乱序:
通过预编译的方式,使用id进行查询,没能得到正确的结果:
order by失效,因为此时执行的sql语句为:
代码语言:javascript复制select * from user order by ‘id’
不通过预编译传参的方式进行查询,order by生效:
此时执行的sql语句为:
代码语言:javascript复制select * from user order by id
但不使用预编译,如果参数可控又可能存在sql注入,这种情况只能配合关键字黑白名单过滤的方式进行防护了。
Part.3
结语
以上就是今天的全部内容啦~