时人不识凌云木,直待凌云始道高。这篇文章主要讲述JAVA SQL注入测试相关的知识,希望能为你提供帮助。
一、说明
SQL注入漏洞由于人为对输入的数据进行了恶意的拼接,而程序又没有进行判断过滤或者处理不恰当,导致程序将用户输入的恶意代码被作为SQL语句执行。本篇测试java代码中的SQL注入,后面进一步测试了流行的MyBatis中的SQL注入问题。
二、测试对象准备
(一)JAVA测试代码,先使用拼接SQL语句的方式:
@Controllerpublic class LoginController
public static final Logger logger = (Logger) LogManager.getLogger(LoginController.class);
@RequestMapping("/login_action")
public String login(@RequestParam String username, @RequestParam String
password, Model model) throws SQLException, ClassNotFoundException
try
Connection connection =
SqlConnectionUtil.GetSqlConnection();
//
语句拼接,造成SQL注入
Statement statement =
connection.createStatement();
String sql = "select
* from userinfo where username="+username+"
and password ="+password+";
";
System.out.println(sql);
ResultSet rs = statement.executeQuery(sql);
//
使用预编译//
String sql =
"select * from userinfo where username=?
and password =?;
";
//
PreparedStatement
preparedStatement = connection.prepareStatement(sql);
//
preparedStatement.setString(1,username);
//
preparedStatement.setString(2,password);
//
ResultSet rs =
preparedStatement.executeQuery();
logger.info("info: " + sql);
System.out.println("查询结果:");
if (rs.next())
String name =
rs.getString("username");
System.out.println(name);
logger.fatal("User: "+ username+" is logged in !");
model.addAttribute("msg","welcome you :"+name);
else
model.addAttribute("msg","Sorry,Your Username or Password is wrong! ");
catch (Exception e)
e.printStackTrace();
return "test";
(二)前台登录页面
三、测试
(一)在用户名处使用万能密码尝试登录:
点击“登录”后,登录成功。
(二)SQLMAP神器测试
由于是POST登录,先将浏览器访问通过BURP截取保存为login.txt文件测试,测试的时候可以使用-p指定参数:
D:\\sqlmap-master>
python sqlmap.py -r
sqlmaptesturl\\login.txt
查看后台的日志:
四、修改使用预编译,再次扫描未发现SQL注入。
五、MyBatis测试
MyBatis是一款数据持久层框架,它用来简化开发人员对SQL的操作,通过MyBatis开发人员可以通过xml文件操作数据库,只需要将SQL语句编写到xml文件中即可。另外,MyBatis在通过#号传递参数时,底层也采用了PreparedStatement
SQL预编译的形式,有效的缓解了SQL注入的问题。下面就针对MyBatis做一些简单的SQL注入测试。
六、TestController配置:
下面是用户访问入口的代码,分别是通过id获取用户信息以及通过name获取用户信息:
@RequestMapping("/getUserListById")
public User getUserListById(@RequestParam(value = "https://www.songbingjia.com/android/id") String userid)
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = (User) userDao.getUserListById(userid);
System.out.println(user);
sqlSession.close();
return user;
@RequestMapping("/getUserListByName")
public User getUserListByName(@RequestParam(value = "https://www.songbingjia.com/android/name") String name)
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = (User) userDao.getUserListByName(name);
System.out.println(user);
sqlSession.close();
return user;
七、UserMapper.xml中的配置
在UserMapper.xml中写入SQL语句:第一条是通过id获取用户列表,这里使用“#“号;第二条是通过name获取用户列表,这是使用的是”$”号,如下:
<
!—通过id查询用户,使用#号-->
<
select id="getUserListById" parameterType="String"
resultType="com.yang.pojo.User">
select * from mybatis.user where id = #id
<
/select>
<
!—通过name查询用户,使用$号-->
<
select id="getUserListByName" parameterType="String" resultType="com.yang.pojo.User">
select * from mybatis.user where name = $name
<
/select>
八、结果查看
(一)
通过浏览器访问进行功能测试:
通过name获取用户列表:
通过id获取用户列表:
(二)
通过日志信息查看SQL语句:
注意看到getUserListByName通过名字查询,由于在UserMapper中使用的是”$”号,因此SQL语句直接将用户输入进行了拼接,而getUserListById使用的是“#”号,因此使用了“?”号占位。
九、下面使用sqlmap神器跑一下看看:
1、 python sqlmap.py -u
"http://localhost:8080/getUserListByName?name=1" 扫描出来一堆漏洞,如下:
2、 python sqlmap.py -u "http://localhost:8080/getUserListById?id=1"
未扫描出漏洞,如下:
十、接下来看一下like语句
(一)先看一下like语句的语法:
select * from mybatis.user where name like %王%;
(二)UserMapper.xml中的配置,注意这里写的%$name%:
<
select id="getUserLike" parameterType="String" resultType="com.yang.pojo.User">
select * from mybatis.user where name like %$name%
<
/select>
(三)TestController配置:
@RequestMapping("/getUserLike")
public List<
User>
getUserLike(@RequestParam(value = "https://www.songbingjia.com/android/name") String name)
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<
User>
userList = userDao.getUserLike(name);
for (User user:userList)
System.out.println(user);
sqlSession.close();
return userList;
(四)浏览器访问:
(五)看SQL执行日志,显示进行了语句拼接,如下:
(六)用SQLMAP扫一遍,爆出一堆漏洞:
(七)把UserMapper修改一下,使用“#”替换“$”,如下:
<
select id="getUserLike" parameterType="String" resultType="com.yang.pojo.User">
select * from mybatis.user where name like %#name%
<
/select>
这个时候会报错:
### Error querying database.
Cause: org.apache.ibatis.type.TypeException:
Could not set parameters for mapping: ParameterMappingproperty=name,
mode=IN, javaType=class java.lang.String, jdbcType=null, numericScale=null,
resultMapId=null, jdbcTypeName=null, expression=null. Cause:
org.apache.ibatis.type.TypeException: Error setting non null for parameter #1
with JdbcType null . Try setting a different JdbcType for this parameter or a
different configuration property. Cause: java.sql.SQLException: Parameter index
out of range (1 >
number of parameters, which is 0).
类型不匹配,获取不到参数(具体原因我也没有研究清楚,所有的参数类型都是匹配的,但是将“#”换为”$”后就正确了)。
(八)再修改一下UserMapper.xml的配置,如下:
<
select id="getUserLike" parameterType="String" resultType="com.yang.pojo.User">
select * from mybatis.user where name like "%"#name"%"
<
/select>
(九)通过浏览器访问正常,然后查看日志,这里使用了?进行占位,如下:
(十)这时候再使用SQLMAP扫描,已经扫不到漏洞了,如下:
十一、
总结
【JAVA SQL注入测试】本篇前半部分介绍了JAVA环境中的SQL语句拼接容易导致SQL注入问题,使用PreparedStatement
预编译后可以避免SQL注入。后半部分说明了MyBatis中常见的两种参数传递方式$value以及#value,这两种方式对传入的参数的处理方式是不一样的,当使用#value时,MyBatis会使用#value这种方式。
推荐阅读
- 基于ansible在远程centos服务器docker环境安装kafka
- 计算机类SQL语言例子汇总
- 90天Java---mybatis与mybatis plus-1
- Clickhouse重复数据处理
- mysql|mysql删除重复数据,一条sql就搞定
- 全国超10亿用户!AntDB数据库的电信核心交易替换之路
- 面试经验|常见的字符串常量池必问面试题
- 分布式|redis管道是什么鬼()
- 浮动静态路由