Java代码审计-SQL注入

前言

今天学习了java代码中导致的sql注入的相关知识,浅浅的记录一下。

一、SQL注入简介

SQL 注入是因为程序未能正确对用户的输入进行检查,将用户输入以拼接的方式带入 SQL 语句中,影响原 SQL 语句的逻辑,导致了 SQL 注入的产生。

SQL 注入漏洞可能会造成服务器的数据库信息泄露、数据被窃取、网页被篡改,甚至可能会造成网站被挂马服务器被远程控制、被安装后门等。

二、Java主要执行SQL语句的方式

1.JDBC

JDBC是Java连接数据库的标准API。它提供了一组接口和类,用于与关系型数据库进行交互。通过JDBC,可以连接到各种数据库(如MySQL、Oracle、SQL Server等),执行SQL语句、事务管理和结果集处理等操作。

2.MyBatis

ORM框架,允许将Java对象和关系型数据库之间进行映射,进而实现数据库操作。

Mybatis 是一个持久层框架,它封装数据连接、获取结果集等一系列的繁琐操作,使用者只需关注操作 SQL 语句的编写,通过 xml 或注解的方式就能将数据库中的数据与对象形成映射进行返回。

Mybatis 的学习曲线相对较低,适合对 SQL 有深入理解的开发者。

3.Hibernate

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将java对象与数据库表建立映射关系,是一个全自动的orm框架。

Hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

Hibernate 的学习曲线较高,需要理解其 ORM 模型和配置。

三、JDBC方式产生的漏洞

1.Statement方式

java.sql.Statement 是 Java JDBC 下执行 SQL 语句的一种原生方式,执行语句时需要通 过拼接来执行。若拼接的语句没有经过过滤,将出现 SQL 注入漏洞。

//采用拼接的方式 
String sql = "select * from user where id = "+req.getParameter("id"); 
 Statement st = con.createStatement(); //创建Statement对象
 ResultSet rs = st.executeQuery(sql); //执行查询

由上述代码可以看到,该方式只是对前端用户输入直接进行sql语句的拼接,然后代入数据库查询,可导致SQL注入漏洞。

2.PreparedStatement方式

PreparedStatement 会预处理 SQL 语句,为原本需要拼接的参数参数保留一个问号(?)作为占位符。

采用预编译的方式,可以有效地防止SQL注入漏洞。

//sql语句如下  使用?代替之前需要拼接的参数
String sql = "select * from user where id = ?"; 
PreparedStatement pstt = con.prepareStatement(sql); //对sql语句进行预编译
pstt.setInt(1,Integer.parseInt(req.getParameter("id"))); //对里面的参数进行设置 可以理解成将id转换为int后放到第一个?的位置
 ResultSet rs = pstt.executeQuery();//执行查询

像上述这样正确使用预编译的操作是比较安全的,可以有效防止SQL注入。

那么,预编译防止SQL注入怎么做的呢?

  • 对下面代码,输入" 小明’ ",经过测试发现是对特殊符号加入转义字符。
String sql = "select * from user where name = ?";  // sql语句
PreparedStatement st = conn.prepareStatement(sql);  //预编译
st.setString(1, "小明'"); // 参数赋值 sql注入测试
System.out.println(st.toString()); //输出为:select * from user where name = '小明\''

那么,使用预编译的方法就完全避免注入的影响了嘛?、

  • 答案是否定的。

经过测试发现,预编译不会对%进行转移,这正好是SQL语句like查询需要的。

假如代码如下所示,则会遇到SQL注入的风险。

String sql = "select * from user where name like ?";  // 含有参数 
st = conn.prepareStatement(sql);
st.setString(1, "%小明%" + "%"); // 参数赋值
System.out.println(st.toString()); //输出为select * from user where name like '%小明%%'

这样就改变了原本查询的意思。

另外,预编译也不会对_进行转义

那么,还有个问题,就是不是所有的语句都能够使用预编译来解决的。

  • 比如代码中使用order by语句时,这种特殊情况无法使用预编译。order by 子句后面需要加字段名或者字段位置,而预编译后产生的是字符串,不再是字段名,这种情况下只能使用sql语句拼接的办法。
  • 所以使用这些特殊语句时,要注意对输入进行过滤。

四、MyBatis方式产生的漏洞

1.两种参数符号造成的SQL注入

MyBatis支持两种参数符号,一种是#,另一种是$。

  • 当使用#时,MyBatis底层会使用预编译的机制。
  • 使用参数符号$时,MyBatis底层直接用字符串拼接把参数和SQL语句拼接在一起,然后执行。

2.order by、like、in引发注入

  • 与第三部分的描述类似,在mybatis中使用order by语句的话,只能使用参数符号$,即使用字符串拼接的方式,如果没有进行严格过滤,则导致注入。
  • like in 同理

五、Hibernate方式产生的漏洞

1.简介

  • HQL注入:Hibernate中没有对数据进行有效的验证导致恶意数据进入应用程序中造成的。与SQL注入类似。

2.原理

与第三部分、第四部分类似。

参数绑定,这样是安全的

String queryString = "from Item item where item.deion like :searchString”;

List result = session.createQuery(queryString).setString("searchString", searchString).list();

直接拼接是不安全的。

HQL注入利用比较有限。

六、总结

综上所述,主要是考虑代码是否使用了预编译,以及对于一些未使用预编译的特殊语句,是否进行了安全的校验。

参考

  • 33
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值