长亭百川云 - 文章详情

RASP| SQL注入检测与防御

RASP安全技术

69

2024-07-13

    一方面数据映射框架如mybatis、hiberate等在框架底层已经实现了对sql注入的防御,另一方面白盒/黑盒等扫描器也能解决一部分sql注入问题,sql注入的出现风险被大大降低。但是在研发人员未能恰当的使用框架或者sql语句拼接不当的的情况下,仍然可能导致sql注入的风险。本文分析sql注入的几种情况以及RASP在其中的作用。

1.JDBC 拼接不当造成的SQL注入

    JDBC有两种方法执行SQL语句,分别为PrepareStatement和Statement。两个方法的区别在于PrepareStatement会对SQL语句进行预编译,而Statement方法在每次执行时都需要编译,会增大系统开销。理论上PrepareStatement的效率和安全性会比Statement要好,但并不意味着使用PrepareStatement就绝对安全,不会产生SQL注入。

      PrepareStatement方法支持使用‘?’对变量位进行占位,在预编译阶段填入相应的值构造出完整的SQL语句,此时可以避免SQL注入的产生。但开发者有时为了便利,会直接采取拼接的方式构造SQL语句,此时进行预编译则无法阻止SQL注入的产生。如以下代码所示,PrepareStatement虽然进行了预编译,但在以拼接方式构造SQL语句的情况下仍然会产生SQL注入。代码示例如下(若使用“or 1=1”,仍可判断出这段代码存在SQL注入)

`String sql = "select * from user where id =" + req.getParameter("id");``out.println(sql);``try{`    `PreparedStatement pstt = con.prepareStatement(sql);`    `ResultSet re = pstt.executeQuery();`    `while(rs.next()){`        `out.println("<br>id:"+rs.getObject("id"));`        `out.println("<br>name:"+re.getObject("name"));`    `}`    `catch(SQLException e){`        `e.printStackTrace();`    `}``}`

     正确地使用PrepareStatement可以有效避免SQL注入的产生,使用“?”作为占位符时,填入对应字段的值会进行严格的类型检查。将前面的“拼接构造SQL语句”改为如下“使用占位符构造SQL语句”的代码片段,即可有效避免SQL注入的产生。

`PrintWriter out = resp.getWriter();``String sql = "select * from user where id = ?"``out.println(sql);``try{`    `PreparedStatement pstt = con.prepareStatement(sql);`    `pstt.setInt(1,Integer.parseInt(req.getParameter("id")));`    `ResultSet rs = pstt.executeQuery();`    `// sql执行结果的代码省去....``}`

2.框架使用不当造成SQL注入

    如今的Java项目或多或少会使用对JDBC进行更抽象封装的持久化框架,如MyBatis和Hibernate。通常,框架底层已经实现了对SQL注入的防御,但在研发人员未能恰当使用框架的情况下,仍然可能存在SQL注入的风险。

Mybatis框架

    MyBatis框架的思想是将SQL语句编入配置文件中,避免SQL语句在Java程序中大量出现,方便后续对SQL语句的修改与配置。MyBatis中使用parameterType向SQL语句传参,在SQL引用传参可以使用#{Parameter}和${Parameter}两种方式

使用#{Parameter}构造SQL的代码如下所示

`<select id="getUsername" resultType="com.example.bean.User">`    `select id,name,age from user where name #{name}``<select>`

    从Debug回显的SQL语句执行过程可以看出,使用#{Parameter}方式会使用“?”占位进行预编译,因此不存在SQL注入的问题。用户可以尝试构造“name”值为“z1ng or 1=1”进行验证。回显如下,由于程序未查询到结果出现了空指针异常,因此此时不存在SQL注入。

使用${Parameter}构造SQL的代码如下所示:

`<select id = "getUsername" resultType = "com.example.bean.User">`    `select id,name,age from user where name = ${name}``<select>`

name”值被拼接进SQL语句之中,因此此时存在SQL注入。${Parameter}采用拼接的方式构造SQL,在对用户输入过滤不严格的前提下,此处很可能存在SQL注入。

Hibernate

    Hibernate是一种ORM框架,全称为 Object_Relative DateBase-Mapping,Hibernate框架是Java持久化API(JPA)规范的一种实现方式。Hibernate 将Java 类映射到数据库表中,从 Java 数据类型映射到 SQL 数据类型。Hibernate是目前主流的Java数据库持久化框架,采用Hibernate查询语言(HQL)注入

    HQL的语法与SQL类似,受语法的影响,HQL注入在实际漏洞利用上具有一定的限制。

3.jrasp mysql检测模块

      不同sql client版本,hook类差别大,这里以mysql8.x 为例子说明。

1)可配置参数:

2)sql拼接hook

com.mysql.cj.jdbc.StatementImpl

3)sql 预编译hook

com.mysql.cj.jdbc.ClientPreparedStatement,com.mysql.cj.jdbc.PreparedStatement

4)检测算法

4.sql注入实战

存在sql拼接的业务代码如下

正常sql(返回用户自己的数据)

sql注入(返回了全部用户数据)

5.检测与防御

    值得注意的是不同于复杂的正则规则检测, jrasp内置了 sql 注入词法分析防火墙,单条sql检测时间在0.1ms内完成,误报/漏报率极低。

---------------------------------------------------------------------------

🔥🔥🔥国内技术领先的开源RASP社区 https://www.jrasp.com

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2