# 一、漏洞环境信息

JDBC: http://127.0.0.1:8080/sqlinject/jdbc?id=1
JdbcTemplate: http://127.0.0.1:8080/sqlinject/jdbctemplate?id=1
mybatis: http://127.0.0.1:8080/sqlinject/mybatis?id=1

payload: python sqlmap.py -u "http://127.0.0.1:8080/sqlinject/jdbc?id=1"

# 二、修复说明

# Jdbc

java 提供的对数据库操作的原生接口

# 代码举例

Statement:一般用于静态SQL(无参数)的执行,场景用于批处理,如下中存在id注入


Class.forName("com.mysql.cj.jdbc.Driver");  //加载驱动
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mytest?characterEncoding=utf8", "root", "123456");   //连接mysql,获得连接
String sql = “select * from tablex where id = ” + id;
Statement statement = connect.createStatement();  //获得statement对象
ResultSet resultSet = statement.executeQuery(sql);  //执行sql获得结果集
.........

prepareStatement:用于执行动态SQL(传参数),id注入问题修复

Class.forName("com.mysql.cj.jdbc.Driver");  //加载驱动
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mytest?characterEncoding=utf8", "root", "123456");   //连接mysql,获得连接
String sql =”select * from tablex where id = ?”; // ?代表参数占位符
PreparedStatement ps = connect.prepareStatement(sql); //获得preoarestatement对象
ps.setObject(i,args[i]);  //设置预编译参数
ResultSet resultSet = ps.executeQuery(); //执行sql获得结果集
..........

# JdbcTemplate

spring提供的对JDBC进一步封装的方案

# 代码举例

注入代码:id存在注入

private JdbcTemplate jdbcTemplate=new JdbcTemplate();
String sql = "select * from Userinfo where id = " + id; //SQL拼接
Userinfo userinfo = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Userinfo>(Userinfo.class));

无注入代码

private JdbcTemplate jdbcTemplate=new JdbcTemplate();
String sql = "select * from Userinfo where id = ?"; //占位符
Userinfo userinfo = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Userinfo>(Userinfo.class),id);

# mybatis

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

代码流程说明

  • http://127.0.0.1:8080/sqlinject/mybatis?id=1

mybatis的sql语句是保存在mapper的xml文件中的,因此只需要关注xml中的sql语句即可。其中${}表示拼接变量,#{}才是预编译参数

# 三、小结

  • 成因:SQL语句拼接
  • 位置:Dao层
  • 修复:过滤/ESAPI/预编译处理(推荐******)
    • 预编译无法覆盖的场景:order by /group by,白名单过滤