【Java 代码审计入门-02】SQL 漏洞原理与实际案例介绍
字数 883 2025-08-25 22:58:46

Java 代码审计入门:SQL 漏洞原理与实际案例

0x00 前言

本系列文章旨在为具备Java基本语法基础的学习者提供系统的Java代码审计教程。本文将重点讲解SQL注入漏洞的原理、实际案例及修复方案。

0x01 环境准备

数据库设置

CREATE DATABASE sec_sql CHARSET utf8;

CREATE TABLE `admin` (
  `uid` int(11) NOT NULL AUTO_INCREMENT COMMENT 'uid',
  `username` varchar(100) NOT NULL COMMENT '账号',
  `password` varchar(100) NOT NULL COMMENT '密码',
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

CREATE TABLE `userinfo` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(100) NOT NULL COMMENT '名称',
  `age` int(11) NOT NULL COMMENT '年龄',
  `content` varchar(100) NOT NULL COMMENT '联系方式',
  `address` varchar(255) NOT NULL COMMENT '家庭地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

测试项目结构

  • Servlet层接收请求
  • 调用UserInfoServiceImpl
  • UserInfoServiceImpl调用UserInfoDaoImpl
  • UserInfoDaoImpl操作数据库
  • 返回UserInfo对象并最终显示到info.jsp

0x02 SQL注入原理

SQL注入是通过将恶意SQL命令插入应用程序的HTTP请求中,在服务器端被接收后参与数据库操作,最终欺骗服务器执行恶意SQL命令。

漏洞代码示例

public UserInfo UserInfoFoundDao(String id){
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    UserInfo userinfo = null;
    try{
        Class.forName("com.mysql.cj.jdbc.Driver");
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sec_sql","root","admin888");
        String sql = "select * from userinfo where id = " + id;  // 直接拼接用户输入
        ps = conn.prepareStatement(sql);
        rs = ps.executeQuery();
        // ... 结果处理
    }
    // ...
}

攻击示例

  1. 基础注入:id=1 and 1=1
  2. 联合查询获取管理员凭证:
    id=2 union select 1,2,3,group_concat(username),group_concat(password) from admin--
    

0x03 修复方案

1. 使用预编译

String sql = "select * from userinfo where id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1,id);  // 参数化查询

注意:预编译并非绝对安全,以下情况仍需注意:

  • order by子句不能使用预编译
  • like子句需要特殊处理
  • in子句需要特殊处理

2. 修改数据类型

public UserInfo UserInfoFoundDao(int id){  // 使用int而非String
    // ...
    String sql = "select * from userinfo where id = " + id;
    // ...
}

3. 其他防御措施

  • 输入验证和过滤
  • 最小权限原则
  • 错误信息处理
  • 使用ORM框架的安全方法

0x04 实际案例:CVE-2019-9615分析

案例介绍

OFCMS v1.1.3之前版本存在后台SQL注入漏洞,位于admin/system/generate/create?sql=路径。

漏洞代码

public void create() {
    try {
        String sql = getPara("sql");  // 直接获取用户输入
        Db.update(sql);  // 直接执行SQL
        rendSuccessJson();
    } catch (Exception e) {
        e.printStackTrace();
        rendFailedJson(ErrorCode.get("9999"), e.getMessage());
    }
}

攻击示例

update of_cms_link set link_name=updatexml(1,concat(0x7e,(user())),0) where link_id = 4

修复建议

  1. 限制后台功能权限
  2. 重写业务功能,避免直接执行用户输入
  3. 过滤危险关键字(黑名单)
  4. 设置SQL操作白名单

0x05 总结

  1. Java中的SQL注入原理与PHP类似,都是由于未正确处理用户输入
  2. 预编译是主要防御手段,但需注意特殊情况
  3. 框架使用不当(如Mybatis的like/order by/in,Hibernate的createQuery)仍可能导致注入
  4. 实际审计中需关注数据流从用户输入到SQL语句的全过程

0x06 参考资源

Java 代码审计入门:SQL 漏洞原理与实际案例 0x00 前言 本系列文章旨在为具备Java基本语法基础的学习者提供系统的Java代码审计教程。本文将重点讲解SQL注入漏洞的原理、实际案例及修复方案。 0x01 环境准备 数据库设置 测试项目结构 Servlet层接收请求 调用UserInfoServiceImpl UserInfoServiceImpl调用UserInfoDaoImpl UserInfoDaoImpl操作数据库 返回UserInfo对象并最终显示到info.jsp 0x02 SQL注入原理 SQL注入是通过将恶意SQL命令插入应用程序的HTTP请求中,在服务器端被接收后参与数据库操作,最终欺骗服务器执行恶意SQL命令。 漏洞代码示例 攻击示例 基础注入: id=1 and 1=1 联合查询获取管理员凭证: 0x03 修复方案 1. 使用预编译 注意 :预编译并非绝对安全,以下情况仍需注意: order by 子句不能使用预编译 like 子句需要特殊处理 in 子句需要特殊处理 2. 修改数据类型 3. 其他防御措施 输入验证和过滤 最小权限原则 错误信息处理 使用ORM框架的安全方法 0x04 实际案例:CVE-2019-9615分析 案例介绍 OFCMS v1.1.3之前版本存在后台SQL注入漏洞,位于 admin/system/generate/create?sql= 路径。 漏洞代码 攻击示例 修复建议 限制后台功能权限 重写业务功能,避免直接执行用户输入 过滤危险关键字(黑名单) 设置SQL操作白名单 0x05 总结 Java中的SQL注入原理与PHP类似,都是由于未正确处理用户输入 预编译是主要防御手段,但需注意特殊情况 框架使用不当(如Mybatis的like/order by/in,Hibernate的createQuery)仍可能导致注入 实际审计中需关注数据流从用户输入到SQL语句的全过程 0x06 参考资源 OFCMS官方仓库 CVE-2019-9615详情 MySQL监控工具 示例代码仓库