前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【JAVA代码审计】从零开始的JDBC下的SQL注入审计

【JAVA代码审计】从零开始的JDBC下的SQL注入审计

作者头像
一名白帽的成长史
发布2022-11-11 15:33:45
6840
发布2022-11-11 15:33:45
举报

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

结语

以上就是今天的全部内容啦~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-09-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一名白帽的成长史 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档