JAVA代码审计篇-SQL注入
字数 1244 2025-08-11 08:35:47

Java代码审计之SQL注入漏洞详解

1. SQL注入漏洞简介

SQL注入攻击是黑客利用SQL注入漏洞对数据库进行攻击的常用手段之一。攻击者通过浏览器或其他客户端将恶意SQL语句插入到网站参数中,网站应用程序未经过滤便将恶意SQL语句带入数据库执行。

危害影响

  • 数据库信息泄露
  • 数据被窃取
  • 网页被篡改
  • 网站被挂马
  • 服务器被远程控制
  • 被安装后门

分类

  • 按输入类型
    • 数字型注入
    • 字符串型注入
  • 按攻击方式
    • 联合查找型注入
    • 报错注入
    • 时间盲注
    • 布尔盲注

2. SQL注入的条件

  1. 输入用户可控
  2. 输入直接或间接拼入SQL语句执行

3. 审计方法

审计流程

  1. 根据SELECTUPDATE等SQL关键字定位代码片段
  2. 检查SQL语句中是否存在变量引用
  3. 跟踪变量是否可控

自动化工具

  • Fortify等静态代码分析工具

Java语言特性

Java是强类型语言,审计时应:

  1. 找到所有包含SQL语句的点
  2. 观察传参类型是否为String类型(只有String类型才可能SQL注入)

4. Java中执行SQL的几种方式

4.1 使用JDBC的Statement

Statement是Java JDBC下执行SQL语句的原生方式,通过拼接执行SQL语句。

风险:若拼接未经过滤,将出现SQL注入漏洞。

示例代码

Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(DBURL, DBUser, DBPassWord);
Statement state = conn.createStatement();
String sql = "SELECT * FROM user WHERE id=" + id;
state.executeQuery(sql);

4.2 使用JDBC的PreparedStatement

PreparedStatementStatement的子接口,包含已编译的SQL语句,使用参数化查询。

优势

  • 预编译特性,执行更快
  • 有效防止SQL注入

使用方法

Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(DBURL, DBUser, DBPassWord);
String sql = "SELECT * FROM user WHERE id = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, id);
ResultSet resultSet = preparedStatement.executeQuery();

4.3 使用MyBatis框架

MyBatis是一个Java持久化框架,通过XML或注解将对象与SQL语句关联。

两种使用方式

  1. 注解方式
@Select("select * from Blog where id = #{id}")
Blog selectBlog(int id);
  1. XML映射方式
<select id="selectBlog" parameterType="int" resultType="Blog">
    select * from Blog where id = #{id}
</select>

5. 常见SQL注入漏洞代码

5.1 SQL语句参数直接动态拼接

漏洞代码

String id = request.getParameter("id");
res = st.executeQuery("SELECT * FROM \"IWEBSEC\".\"user\" WHERE \"id\"=" + id);

攻击示例

http://www.any.com/index.jsp?id=1 union select null,null,SYS_CONTEXT('USERENV','CURRENT_USER') from dual

5.2 预编译有误

错误示例

String username = "user%' or '1'='1'#";
String sql = "SELECT * FROM user where id = ?";
if (!CommonUtils.isEmptyStr(username)) 
    sql += " and username like '%" + username + "%'";

问题:虽然id使用了参数化查询,但username仍使用拼接方式。

5.3 order by注入

特殊场景:order by子句不能使用参数化查询,必须拼接字段名。

漏洞代码

String id = "2 or 1=1";
String sql = "SELECT * FROM user order by " + id;

防御:对order by字段进行严格过滤。

5.4 #和_模糊查询问题

风险:预编译查询不会对%_进行转义,可能导致恶意模糊查询。

示例

String username = "%user%";
// 会作为通配符处理,而非普通字符

6. 防御措施

  1. 优先使用PreparedStatement进行参数化查询
  2. 避免直接拼接SQL语句,特别是用户输入
  3. 对order by等特殊场景进行严格过滤
  4. 对模糊查询中的特殊字符进行转义处理
  5. 使用ORM框架如MyBatis时,确保正确使用参数化查询
  6. 输入验证:对用户输入进行严格验证和过滤

7. 最佳实践

  1. 在代码审查时重点关注SQL语句构建方式
  2. 使用自动化工具辅助检测潜在漏洞
  3. 对数据库操作进行统一封装,避免分散的SQL拼接
  4. 定期进行安全测试和渗透测试
  5. 保持框架和库的最新版本,及时修复已知漏洞
Java代码审计之SQL注入漏洞详解 1. SQL注入漏洞简介 SQL注入攻击是黑客利用SQL注入漏洞对数据库进行攻击的常用手段之一。攻击者通过浏览器或其他客户端将恶意SQL语句插入到网站参数中,网站应用程序未经过滤便将恶意SQL语句带入数据库执行。 危害影响 数据库信息泄露 数据被窃取 网页被篡改 网站被挂马 服务器被远程控制 被安装后门 分类 按输入类型 : 数字型注入 字符串型注入 按攻击方式 : 联合查找型注入 报错注入 时间盲注 布尔盲注 2. SQL注入的条件 输入用户可控 输入直接或间接拼入SQL语句执行 3. 审计方法 审计流程 根据 SELECT 、 UPDATE 等SQL关键字定位代码片段 检查SQL语句中是否存在变量引用 跟踪变量是否可控 自动化工具 Fortify等静态代码分析工具 Java语言特性 Java是强类型语言,审计时应: 找到所有包含SQL语句的点 观察传参类型是否为String类型(只有String类型才可能SQL注入) 4. Java中执行SQL的几种方式 4.1 使用JDBC的Statement Statement 是Java JDBC下执行SQL语句的原生方式,通过拼接执行SQL语句。 风险 :若拼接未经过滤,将出现SQL注入漏洞。 示例代码 : 4.2 使用JDBC的PreparedStatement PreparedStatement 是 Statement 的子接口,包含已编译的SQL语句,使用参数化查询。 优势 : 预编译特性,执行更快 有效防止SQL注入 使用方法 : 4.3 使用MyBatis框架 MyBatis是一个Java持久化框架,通过XML或注解将对象与SQL语句关联。 两种使用方式 : 注解方式 : XML映射方式 : 5. 常见SQL注入漏洞代码 5.1 SQL语句参数直接动态拼接 漏洞代码 : 攻击示例 : 5.2 预编译有误 错误示例 : 问题 :虽然id使用了参数化查询,但username仍使用拼接方式。 5.3 order by注入 特殊场景 :order by子句不能使用参数化查询,必须拼接字段名。 漏洞代码 : 防御 :对order by字段进行严格过滤。 5.4 #和_ 模糊查询问题 风险 :预编译查询不会对 % 和 _ 进行转义,可能导致恶意模糊查询。 示例 : 6. 防御措施 优先使用PreparedStatement 进行参数化查询 避免直接拼接SQL语句 ,特别是用户输入 对order by等特殊场景 进行严格过滤 对模糊查询中的特殊字符 进行转义处理 使用ORM框架 如MyBatis时,确保正确使用参数化查询 输入验证 :对用户输入进行严格验证和过滤 7. 最佳实践 在代码审查时重点关注SQL语句构建方式 使用自动化工具辅助检测潜在漏洞 对数据库操作进行统一封装,避免分散的SQL拼接 定期进行安全测试和渗透测试 保持框架和库的最新版本,及时修复已知漏洞